| name | mission-control-ui |
| description | Skill for using the standardized UI components in Mission Control dashboard. Use these components instead of duplicating patterns. |
Mission Control UI Component Library
Skill for using the standardized UI components in Mission Control dashboard.
Overview
The @/components/ui-lib directory contains reusable React components for building consistent dashboard views. Always use these components instead of duplicating patterns.
Location
packages/mission-control/src/components/ui-lib/
├── index.ts # Exports all components
├── page-header.tsx # Title + description + badges
├── stat-card.tsx # Single stat with icon
├── stat-grid.tsx # Grid of stat cards
├── category-nav.tsx # Category navigation sidebar
├── item-list.tsx # Scrollable list with items
├── search-bar.tsx # Search input with button
├── empty-state.tsx # Empty data placeholder
├── timestamp.tsx # Formatted timestamp
├── badge-list.tsx # List of badges
├── loading-state.tsx # Loading spinner
└── content-card.tsx # Card with title and icon
Usage Examples
PageHeader
import { PageHeader } from "@/components/ui-lib";
<PageHeader
title="Perennial Memory"
description="Long-term semantic storage"
badges={[
{ label: "memories", value: 42 },
{ label: "size", value: "1.2 MB" }
]}
/>
StatGrid
import { StatGrid } from "@/components/ui-lib";
import { Cpu, MemoryStick, Thermometer } from "lucide-react";
<StatGrid
columns={3}
stats={[
{ label: "CPU", value: "45%", icon: Cpu, iconColor: "text-green-400" },
{ label: "Memory", value: "6.2 GB", icon: MemoryStick },
{ label: "Temp", value: "52°C", icon: Thermometer },
]}
/>
CategoryNav
import { CategoryNav } from "@/components/ui-lib";
import { Folder } from "lucide-react";
<CategoryNav
title="Categories"
icon={Folder}
categories={[
{ name: "learning", count: 25 },
{ name: "decision", count: 6 },
]}
selected={selectedCategory}
onSelect={setSelectedCategory}
allLabel="Recent"
allCount={42}
/>
ItemList
import { ItemList } from "@/components/ui-lib";
import { Database } from "lucide-react";
import { Timestamp, BadgeList } from "@/components/ui-lib";
<ItemList
title="Recent Memories"
icon={Database}
badge={42}
items={memories}
maxHeight="h-[500px]"
onSelect={(mem) => console.log(mem)}
renderItem={(mem) => (
<div>
<Timestamp timestamp={mem.timestamp} />
<p className="text-sm line-clamp-3">{mem.content}</p>
<BadgeList items={mem.tags} max={3} />
</div>
)}
/>
SearchBar
import { SearchBar } from "@/components/ui-lib";
<SearchBar
placeholder="Search memories..."
onSearch={(query) => performSearch(query)}
/>
Timestamp
import { Timestamp } from "@/components/ui-lib";
<Timestamp timestamp="2026-03-17T02:32:34.465Z" />
<Timestamp timestamp={new Date()} format="relative" />
<Timestamp timestamp={null} /> {}
BadgeList
import { BadgeList } from "@/components/ui-lib";
<BadgeList
items={["success", "api", "auth"]}
colorMap={{ error: "bg-red-500/20 text-red-400" }}
max={3}
/>
EmptyState
import { EmptyState } from "@/components/ui-lib";
import { Inbox } from "lucide-react";
<EmptyState
icon={Inbox}
title="No memories found"
description="Try adjusting your search query"
/>
LoadingState
import { LoadingState } from "@/components/ui-lib";
<LoadingState message="Loading memories..." />
ContentCard
import { ContentCard } from "@/components/ui-lib";
import { Settings } from "lucide-react";
<ContentCard
title="Alert Rules"
icon={Settings}
badge={rules.length}
>
{/* Card content */}
</ContentCard>
DRY Principles
- Always import from
@/components/ui-lib - Never copy component logic
- Use Timestamp for dates - Handles invalid dates gracefully
- Use CategoryNav for filtering - Consistent styling across views
- Use StatGrid for metrics - Responsive grid with icons
- Use EmptyState for empty data - Consistent placeholder UI
Component Props Reference
| Component | Key Props | Purpose |
|---|
| PageHeader | title, description, badges | Page title section |
| StatCard | label, value, icon | Single metric card |
| StatGrid | stats[], columns | Grid of metrics |
| CategoryNav | categories[], selected, onSelect | Category sidebar |
| ItemList | items[], renderItem | Scrollable list |
| SearchBar | placeholder, onSearch | Search input |
| EmptyState | title, description, action | No data placeholder |
| Timestamp | timestamp, format | Date formatting |
| BadgeList | items[], max, colorMap | Tag badges |
| LoadingState | message | Loading spinner |
| ContentCard | title, icon, children | Card container |
When to Create New Components
Create new components ONLY when:
- A UI pattern is used in 3+ views
- The pattern has consistent styling needs
- It encapsulates complex logic
Add new components to ui-lib/index.ts exports.