Admin Portal
A multi-page admin portal with user management, roles, permissions, and system settings.
Alert Dialog
Avatar
Badge
Breadcrumb
Button
Card
Checkbox
Collapsible
Data Table
Dialog
Dropdown Menu
Empty
Form Field Input
Form Field Select
Input
Pagination
Popover
Progress
Scroll Area
Select
Separator
Sidebar
Switch
Tabs
Tooltip
Preview
Open full demoUser Management
Manage users, assign roles, and control access.
User | Role | Status | Last Active | ||
|---|---|---|---|---|---|
JD
John Doe
| Super Admin |
Active | Just now | ||
SC
Sarah Chen
| Admin |
Active | 2 minutes ago | ||
MR
Mike Rodriguez
| Editor |
Active | 15 minutes ago | ||
EW
Emily Watson
| Viewer |
Inactive | 3 days ago | ||
AK
Alex Kim
| Admin |
Active | 1 hour ago | ||
PP
Priya Patel
| Moderator |
Active | 30 minutes ago | ||
JO
James O'Brien
| Editor |
Suspended | 2 weeks ago | ||
LN
Lisa Nakamura
| Viewer |
Active | 5 minutes ago | ||
DO
David Okafor
| Billing |
Active | 45 minutes ago | ||
MG
Maria Garcia
| Super Admin |
Active | 10 minutes ago |
Interactive Demo
This app demo is best experienced in full-screen mode on mobile devices. Tap below to open the interactive demo.
Code
@{
var usersActive = _activePage == "users";
var rolesActive = _activePage == "roles";
var userSettingsActive = _activePage == "user-settings";
var systemSettingsActive = _activePage == "system-settings";
}
<BbSidebarProvider HeightClass="h-dvh" CookieKey=@(null)>
@* Sidebar *@
<BbSidebar Collapsible="false">
<BbSidebarHeader>
<BbDropdownMenu>
<BbDropdownMenuTrigger AsChild="false" Class="w-full">
<div class="flex items-center justify-between px-3 h-12 cursor-pointer hover:bg-sidebar-accent/50 rounded-md transition-colors">
<div class="flex items-center gap-2">
<div class="flex h-7 w-7 items-center justify-center rounded-md bg-primary text-primary-foreground">
<LucideIcon Name="shield-check" class="h-4 w-4" />
</div>
<div>
<span class="text-sm font-semibold">AdminHub</span>
<p class="text-[10px] text-sidebar-foreground/60 -mt-0.5">Acme Corp</p>
</div>
</div>
<LucideIcon Name="chevrons-up-down" class="h-3.5 w-3.5 text-muted-foreground" />
</div>
</BbDropdownMenuTrigger>
<BbDropdownMenuContent MatchTriggerWidth="true">
<BbDropdownMenuLabel>Workspaces</BbDropdownMenuLabel>
<BbDropdownMenuSeparator />
<BbDropdownMenuItem>
<LucideIcon Name="check" class="mr-2 h-4 w-4" />
Acme Corp
</BbDropdownMenuItem>
<BbDropdownMenuItem>
<span class="mr-2 w-4"></span>
Globex Inc
</BbDropdownMenuItem>
<BbDropdownMenuItem>
<span class="mr-2 w-4"></span>
Initech LLC
</BbDropdownMenuItem>
<BbDropdownMenuSeparator />
<BbDropdownMenuItem>
<LucideIcon Name="plus" class="mr-2 h-4 w-4" />
Add Workspace
</BbDropdownMenuItem>
<BbDropdownMenuItem>
<LucideIcon Name="settings" class="mr-2 h-4 w-4" />
Workspace Settings
</BbDropdownMenuItem>
</BbDropdownMenuContent>
</BbDropdownMenu>
</BbSidebarHeader>
<BbSidebarContent Class="flex-1 overflow-auto px-2">
@* Management Group *@
<BbSidebarGroup>
<BbSidebarGroupLabel>Management</BbSidebarGroupLabel>
<BbSidebarMenu>
<BbSidebarMenuItem>
<BbSidebarMenuButton IsActive="usersActive"
Class="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
@onclick='() => SetPage("users")'>
<LucideIcon Name="users" class="h-4 w-4" />
<span>Users</span>
<BbBadge Variant="BadgeVariant.Secondary" Class="ml-auto h-5 px-1.5 text-[10px]">248</BbBadge>
</BbSidebarMenuButton>
</BbSidebarMenuItem>
<BbSidebarMenuItem>
<BbSidebarMenuButton IsActive="rolesActive"
Class="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
@onclick='() => SetPage("roles")'>
<LucideIcon Name="shield" class="h-4 w-4" />
<span>Roles & Permissions</span>
<BbBadge Variant="BadgeVariant.Secondary" Class="ml-auto h-5 px-1.5 text-[10px]">6</BbBadge>
</BbSidebarMenuButton>
</BbSidebarMenuItem>
</BbSidebarMenu>
</BbSidebarGroup>
@* Settings Group *@
<BbSidebarGroup>
<BbSidebarGroupLabel>Settings</BbSidebarGroupLabel>
<BbSidebarMenu>
<BbSidebarMenuItem>
<BbSidebarMenuButton IsActive="userSettingsActive"
Class="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
@onclick='() => SetPage("user-settings")'>
<LucideIcon Name="user-cog" class="h-4 w-4" />
<span>User Settings</span>
</BbSidebarMenuButton>
</BbSidebarMenuItem>
<BbSidebarMenuItem>
<BbSidebarMenuButton IsActive="systemSettingsActive"
Class="hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
@onclick='() => SetPage("system-settings")'>
<LucideIcon Name="sliders-horizontal" class="h-4 w-4" />
<span>System Settings</span>
</BbSidebarMenuButton>
</BbSidebarMenuItem>
</BbSidebarMenu>
</BbSidebarGroup>
</BbSidebarContent>
@* Sidebar Footer - User Profile *@
<BbSidebarFooter>
<BbDropdownMenu>
<BbDropdownMenuTrigger>
<BbButton Variant="ButtonVariant.Ghost" Class="w-full justify-start gap-2 px-2 h-12">
<BbAvatar Size="AvatarSize.Small">
<BbAvatarFallback Class="text-[10px] bg-blue-100 text-blue-700">JD</BbAvatarFallback>
</BbAvatar>
<div class="flex flex-col items-start text-left flex-1 min-w-0">
<span class="text-sm font-medium truncate">John Doe</span>
<span class="text-xs text-muted-foreground truncate">Super Admin</span>
</div>
<LucideIcon Name="chevrons-up-down" class="h-4 w-4 text-muted-foreground" />
</BbButton>
</BbDropdownMenuTrigger>
<BbDropdownMenuContent Side="PopoverSide.Top" Align="PopoverAlign.Start" MatchTriggerWidth="true">
<div class="flex items-center gap-2 p-2">
<BbAvatar Size="AvatarSize.Small">
<BbAvatarFallback Class="text-[10px] bg-blue-100 text-blue-700">JD</BbAvatarFallback>
</BbAvatar>
<div class="flex flex-col min-w-0">
<span class="text-sm font-medium truncate">John Doe</span>
<span class="text-xs text-muted-foreground truncate">john.doe@company.com</span>
</div>
</div>
<BbDropdownMenuSeparator />
<BbDropdownMenuItem OnClick='() => SetPage("user-settings")'>
<LucideIcon Name="settings" class="mr-2 h-4 w-4" />
Settings
</BbDropdownMenuItem>
<BbDropdownMenuSeparator />
<BbDropdownMenuItem>
<LucideIcon Name="log-out" class="mr-2 h-4 w-4" />
Sign Out
</BbDropdownMenuItem>
</BbDropdownMenuContent>
</BbDropdownMenu>
</BbSidebarFooter>
</BbSidebar>
@* Main Content *@
<BbSidebarInset Class="flex flex-col bg-background min-w-0">
@* Header Bar *@
<header class="flex items-center justify-between px-4 py-3 border-b shrink-0">
<div class="flex items-center gap-2">
<BbSidebarTrigger Class="h-8 w-8 md:hidden">
<LucideIcon Name="menu" class="h-4 w-4" />
</BbSidebarTrigger>
<BbBreadcrumb>
<BbBreadcrumbList>
<BbBreadcrumbItem>
<BbBreadcrumbLink Href="#">@BreadcrumbRoot</BbBreadcrumbLink>
</BbBreadcrumbItem>
<BbBreadcrumbSeparator />
<BbBreadcrumbItem>
<BbBreadcrumbPage>@PageTitle</BbBreadcrumbPage>
</BbBreadcrumbItem>
</BbBreadcrumbList>
</BbBreadcrumb>
</div>
<div class="flex items-center gap-1">
@* Notification Bell *@
<BbPopover @bind-Open="_notificationsOpen">
<BbPopoverTrigger>
<BbButton Variant="ButtonVariant.Ghost" Size="ButtonSize.Icon" Class="h-8 w-8 relative">
<LucideIcon Name="bell" class="h-4 w-4" />
@if (_unreadCount > 0)
{
<span class="absolute -top-0.5 -right-0.5 h-4 min-w-4 rounded-full bg-destructive text-destructive-foreground text-[10px] flex items-center justify-center font-medium px-1">
@_unreadCount
</span>
}
</BbButton>
</BbPopoverTrigger>
<BbPopoverContent Align="PopoverAlign.End" Class="w-80 p-0">
<div class="flex items-center justify-between px-4 py-3 border-b">
<h4 class="text-sm font-semibold">Notifications</h4>
<button class="text-xs text-muted-foreground hover:text-foreground transition-colors" @onclick="MarkAllRead">
Mark all read
</button>
</div>
<BbScrollArea MaxHeight="300px">
<div class="divide-y">
@foreach (var notification in _notifications)
{
<div class="flex items-start gap-3 px-4 py-3 hover:bg-accent/50 transition-colors cursor-pointer">
<div class=@($"flex h-8 w-8 shrink-0 items-center justify-center rounded-full {notification.IconBg} mt-0.5")>
<LucideIcon Name="@notification.Icon" class=@($"h-3.5 w-3.5 {notification.IconColor}") />
</div>
<div class="flex-1 min-w-0 space-y-0.5">
<p class="text-sm font-medium leading-tight">@notification.Title</p>
<p class="text-xs text-muted-foreground">@notification.Description</p>
<p class="text-[10px] text-muted-foreground/70">@notification.Time</p>
</div>
@if (!notification.IsRead)
{
<span class="h-2 w-2 rounded-full bg-blue-500 shrink-0 mt-2"></span>
}
</div>
}
</div>
</BbScrollArea>
<div class="border-t px-4 py-2.5 text-center">
<button class="text-xs text-muted-foreground hover:text-foreground transition-colors">
View all notifications
</button>
</div>
</BbPopoverContent>
</BbPopover>
</div>
</header>
@* Page Content *@
<div class="flex-1 min-h-0 overflow-auto">
@switch (_activePage)
{
case "users":
<AdminPortalUsersPage />
break;
case "roles":
<AdminPortalRolesPage />
break;
case "user-settings":
<AdminPortalUserSettingsPage />
break;
case "system-settings":
<AdminPortalSystemSettingsPage />
break;
}
</div>
</BbSidebarInset>
</BbSidebarProvider>
@code {
private string _activePage = "users";
private bool _notificationsOpen;
private int _unreadCount = 3;
private string PageTitle => _activePage switch
{
"users" => "User Management",
"roles" => "Roles & Permissions",
"user-settings" => "User Settings",
"system-settings" => "System Settings",
_ => "Dashboard"
};
private string BreadcrumbRoot => _activePage switch
{
"users" or "roles" => "Admin",
"user-settings" or "system-settings" => "Settings",
_ => "Admin"
};
private void SetPage(string page) => _activePage = page;
private void MarkAllRead()
{
foreach (var n in _notifications) n.IsRead = true;
_unreadCount = 0;
_notificationsOpen = false;
}
private List<NotificationData> _notifications = new()
{
new() { Title = "New user registered", Description = "Sarah Chen created an account", Time = "2 min ago", Icon = "user-plus", IconBg = "bg-blue-100", IconColor = "text-blue-600" },
new() { Title = "Role updated", Description = "Admin role permissions modified", Time = "1 hour ago", Icon = "shield", IconBg = "bg-amber-100", IconColor = "text-amber-600" },
new() { Title = "Login alert", Description = "Unusual login from 192.168.1.200", Time = "3 hours ago", Icon = "shield-alert", IconBg = "bg-red-100", IconColor = "text-red-600" },
new() { Title = "System update", Description = "Version 2.4.1 deployed successfully", Time = "Yesterday", Icon = "settings", IconBg = "bg-gray-100", IconColor = "text-gray-600", IsRead = true },
new() { Title = "Backup completed", Description = "Weekly backup completed (2.1 GB)", Time = "2 days ago", Icon = "database", IconBg = "bg-green-100", IconColor = "text-green-600", IsRead = true },
};
private class NotificationData
{
public string Title { get; set; } = "";
public string Description { get; set; } = "";
public string Time { get; set; } = "";
public string Icon { get; set; } = "";
public string IconBg { get; set; } = "";
public string IconColor { get; set; } = "";
public bool IsRead { get; set; }
}
}