Design System
Layouts
Sidebar, TopBar, and page structure patterns
Layout Patterns
This document defines the layout components and page structure for HRMS.
App Shell Structure
The HRMS app uses a standard dashboard layout:
┌─────────────────────────────────────────────────────────┐
│ TopBar │
├──────────┬──────────────────────────────────────────────┤
│ │ │
│ Sidebar │ Main Content Area │
│ (w-64) │ (bg-background) │
│ │ │
│ │ │
└──────────┴──────────────────────────────────────────────┘
┌────┐
│ AI │ (Fixed bottom-right)
└────┘Sidebar
Desktop Sidebar (Theme-Aware)
The sidebar is theme-aware: white in light mode, dark gray in dark mode.
<aside className="
bg-card text-card-foreground
w-64 h-screen
flex flex-col
border-r border-border
shadow-2xl shadow-black/5
">
{/* Logo Section */}
<div className="h-16 flex items-center px-6 border-b border-border">
<span className="text-xl font-bold text-foreground">HRMS</span>
</div>
{/* Navigation */}
<nav className="flex-1 px-3 py-4 space-y-1 overflow-y-auto">
{/* Active Navigation Item */}
<a className="
flex items-center gap-3 px-3 py-2
bg-primary text-white
rounded-lg
shadow-md shadow-primary/20
">
<LayoutDashboard className="w-5 h-5" />
<span className="font-medium">Dashboard</span>
</a>
{/* Inactive Navigation Item */}
<a className="
flex items-center gap-3 px-3 py-2
text-muted-foreground
rounded-lg
hover:bg-accent hover:text-foreground
transition-colors
">
<Users className="w-5 h-5" />
<span>Employees</span>
</a>
{/* Navigation items... */}
</nav>
{/* User Profile Section */}
<div className="p-4 border-t border-border">
<div className="flex items-center gap-3">
<Avatar className="h-9 w-9">
<AvatarImage src="/avatar.jpg" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">John Doe</p>
<p className="text-xs text-muted-foreground truncate">HR Manager</p>
</div>
<Button variant="ghost" size="icon" className="shrink-0">
<LogOut className="h-4 w-4" />
</Button>
</div>
</div>
</aside>Navigation Items
| State | Background | Text | Shadow |
|---|---|---|---|
| Active | bg-primary | text-white | shadow-md shadow-primary/20 |
| Inactive | transparent | text-muted-foreground | none |
| Hover | bg-accent | text-foreground | none |
Mobile Sidebar (Sheet)
On mobile, the sidebar becomes a slide-out drawer:
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon" className="md:hidden">
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-64 p-0">
{/* Same sidebar content */}
</SheetContent>
</Sheet>TopBar
The TopBar is sticky with backdrop blur:
<header className="
sticky top-0 z-20
w-full h-16
bg-background/80 backdrop-blur-md
border-b border-border
px-4 sm:px-6
flex items-center justify-between
">
{/* Left: Mobile menu + Search */}
<div className="flex items-center gap-4">
{/* Mobile menu button (hidden on desktop) */}
<Button variant="ghost" size="icon" className="md:hidden">
<Menu className="h-5 w-5" />
</Button>
{/* Search */}
<div className="relative hidden sm:block">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search..."
className="pl-9 w-64 bg-muted/50"
/>
</div>
</div>
{/* Right: Actions */}
<div className="flex items-center gap-2">
{/* Quick action button */}
<Button size="sm" className="hidden sm:flex">
<Plus className="h-4 w-4 mr-1" />
Quick Add
</Button>
{/* Theme toggle */}
<Button variant="ghost" size="icon">
<Sun className="h-5 w-5 dark:hidden" />
<Moon className="h-5 w-5 hidden dark:block" />
</Button>
{/* Notifications */}
<Button variant="ghost" size="icon" className="relative">
<Bell className="h-5 w-5" />
<span className="absolute -top-1 -right-1 h-4 w-4 bg-destructive text-destructive-foreground text-xs rounded-full flex items-center justify-center">
3
</span>
</Button>
</div>
</header>TopBar Styling
| Property | Value |
|---|---|
| Height | h-16 (64px) |
| Background | bg-background/80 backdrop-blur-md |
| Border | border-b border-border |
| Position | sticky top-0 z-20 |
Main Content Area
<main className="
flex-1
bg-background
p-6 lg:p-8
overflow-y-auto
">
{/* Page Header */}
<div className="mb-8">
<h1 className="text-2xl font-semibold tracking-tight">Dashboard</h1>
<p className="text-muted-foreground">Welcome back, John!</p>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<StatsCard ... />
<StatsCard ... />
<StatsCard ... />
<StatsCard ... />
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<ContentCard className="lg:col-span-2" />
<ContentCard />
</div>
</main>Content Spacing
| Element | Spacing |
|---|---|
| Page padding (desktop) | p-6 lg:p-8 |
| Page padding (mobile) | p-4 |
| Section margin | mb-8 |
| Card grid gap | gap-6 |
App Shell Component
Complete layout wrapper:
export function AppShell({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen flex bg-background">
{/* Sidebar - hidden on mobile */}
<aside className="hidden md:flex md:w-64 md:flex-col md:fixed md:inset-y-0">
<Sidebar />
</aside>
{/* Main content area */}
<div className="flex-1 md:pl-64">
<TopBar />
<main className="p-6 lg:p-8">
{children}
</main>
</div>
{/* AI Floating Button */}
<AIButton />
</div>
);
}AI Floating Button
Always visible in bottom-right corner:
<motion.button
className="
fixed z-50
bottom-6 right-6 md:bottom-8 md:right-8
w-14 h-14 rounded-full
bg-gradient-to-br from-violet-500 via-purple-500 to-fuchsia-500
text-white
shadow-xl shadow-violet-500/30
hover:shadow-2xl hover:shadow-violet-500/40
hover:scale-105 active:scale-95
transition-all duration-200
flex items-center justify-center
"
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<Sparkles className="w-6 h-6" />
</motion.button>AI Button Position
| Screen Size | Position |
|---|---|
| Mobile | bottom-6 right-6 |
| Desktop | bottom-8 right-8 |
Responsive Breakpoints
Using Tailwind's default breakpoints:
| Breakpoint | Min Width | Usage |
|---|---|---|
sm | 640px | Show search, quick actions |
md | 768px | Show sidebar (fixed) |
lg | 1024px | Larger content padding |
xl | 1280px | Full dashboard grid |
2xl | 1536px | Max content width |
Responsive Patterns
// Sidebar visibility
className="hidden md:flex"
// Grid columns
className="grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
// Padding
className="p-4 sm:p-6 lg:p-8"
// Content span
className="col-span-1 lg:col-span-2"Page Templates
Dashboard Page
export default function DashboardPage() {
return (
<>
{/* Page Header */}
<div className="mb-8">
<h1 className="text-2xl font-semibold tracking-tight">Dashboard</h1>
<p className="text-muted-foreground">Overview of your HR metrics</p>
</div>
{/* Stats Row */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<StatsCard
title="Total Employees"
value="156"
icon={Users}
gradient="from-blue-500 to-blue-600"
/>
{/* ... more stats cards */}
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<ContentCard title="Recent Activity" className="lg:col-span-2">
{/* ... */}
</ContentCard>
<ContentCard title="Quick Actions">
{/* ... */}
</ContentCard>
</div>
</>
);
}List Page (e.g., Employees)
export default function EmployeesPage() {
return (
<>
{/* Page Header with Action */}
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-2xl font-semibold tracking-tight">Employees</h1>
<p className="text-muted-foreground">Manage your team members</p>
</div>
<Button>
<Plus className="w-4 h-4 mr-2" />
Add Employee
</Button>
</div>
{/* Filters/Search */}
<ContentCard className="mb-6">
<div className="flex gap-4">
<Input placeholder="Search employees..." className="max-w-xs" />
<Select>
<SelectTrigger className="w-40">
<SelectValue placeholder="Department" />
</SelectTrigger>
{/* ... */}
</Select>
</div>
</ContentCard>
{/* Data Table */}
<ContentCard>
<Table>
{/* ... */}
</Table>
</ContentCard>
</>
);
}Detail Page (e.g., Employee Profile)
export default function EmployeeDetailPage() {
return (
<>
{/* Back Link */}
<Button variant="ghost" className="mb-4">
<ChevronLeft className="w-4 h-4 mr-1" />
Back to Employees
</Button>
{/* Profile Header Card */}
<ContentCard className="mb-6">
<div className="flex items-start gap-6">
<Avatar className="w-20 h-20">
<AvatarImage src="/avatar.jpg" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<div className="flex-1">
<h1 className="text-2xl font-semibold">John Doe</h1>
<p className="text-muted-foreground">Senior Developer</p>
<div className="flex gap-2 mt-2">
<Badge>Engineering</Badge>
<Badge variant="outline">Full-time</Badge>
</div>
</div>
<Button>Edit Profile</Button>
</div>
</ContentCard>
{/* Tabbed Content */}
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="documents">Documents</TabsTrigger>
<TabsTrigger value="time-off">Time Off</TabsTrigger>
</TabsList>
<TabsContent value="overview">
{/* ... */}
</TabsContent>
</Tabs>
</>
);
}