diff --git a/src/pages/Inventory/Inventory.tsx b/src/pages/Inventory/Inventory.tsx
index 8fa13e7..8aff9fe 100644
--- a/src/pages/Inventory/Inventory.tsx
+++ b/src/pages/Inventory/Inventory.tsx
@@ -1,6 +1,8 @@
import { Link } from 'react-router-dom'
import styles from './Inventory.module.css'
import { PrimitivesSection } from './sections/PrimitivesSection'
+import { CompositesSection } from './sections/CompositesSection'
+import { LayoutSection } from './sections/LayoutSection'
const NAV_ITEMS = [
{ label: 'Primitives', href: '#primitives' },
@@ -30,6 +32,8 @@ export function Inventory() {
+
+
diff --git a/src/pages/Inventory/sections/CompositesSection.module.css b/src/pages/Inventory/sections/CompositesSection.module.css
new file mode 100644
index 0000000..24d9c69
--- /dev/null
+++ b/src/pages/Inventory/sections/CompositesSection.module.css
@@ -0,0 +1,74 @@
+.section {
+ margin-bottom: 40px;
+}
+
+.sectionTitle {
+ font-size: 22px;
+ font-weight: 700;
+ color: var(--text-primary);
+ margin: 0 0 24px;
+}
+
+.componentCard {
+ background: var(--bg-surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ padding: 20px;
+ margin-bottom: 16px;
+ box-shadow: var(--shadow-sm);
+}
+
+.componentTitle {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 0 0 4px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.componentDesc {
+ font-size: 12px;
+ color: var(--text-muted);
+ margin: 0 0 16px;
+}
+
+.demoArea {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: flex-start;
+}
+
+.demoAreaColumn {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ align-items: flex-start;
+}
+
+.demoAreaRow {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: center;
+}
+
+.demoLabel {
+ font-size: 11px;
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.demoGroup {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.demoGroupRow {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
diff --git a/src/pages/Inventory/sections/CompositesSection.tsx b/src/pages/Inventory/sections/CompositesSection.tsx
new file mode 100644
index 0000000..f5a0cd9
--- /dev/null
+++ b/src/pages/Inventory/sections/CompositesSection.tsx
@@ -0,0 +1,598 @@
+import { useState } from 'react'
+import styles from './CompositesSection.module.css'
+import {
+ Accordion,
+ AlertDialog,
+ AreaChart,
+ AvatarGroup,
+ BarChart,
+ Breadcrumb,
+ CommandPalette,
+ DataTable,
+ DetailPanel,
+ Dropdown,
+ EventFeed,
+ FilterBar,
+ LineChart,
+ MenuItem,
+ Modal,
+ Popover,
+ ProcessorTimeline,
+ ShortcutsBar,
+ Tabs,
+ ToastProvider,
+ useToast,
+ TreeView,
+} from '../../../design-system/composites'
+import type { SearchResult } from '../../../design-system/composites'
+import { Button } from '../../../design-system/primitives'
+
+// ── DemoCard helper ──────────────────────────────────────────────────────────
+
+interface DemoCardProps {
+ id: string
+ title: string
+ description: string
+ children: React.ReactNode
+}
+
+function DemoCard({ id, title, description, children }: DemoCardProps) {
+ return (
+
+
{title}
+
{description}
+
{children}
+
+ )
+}
+
+// ── Toast demo inner component (must be inside ToastProvider) ─────────────────
+
+function ToastDemo() {
+ const { toast } = useToast()
+ return (
+
+
+
+
+
+
+ )
+}
+
+// ── Sample data ───────────────────────────────────────────────────────────────
+
+const CHART_SERIES = [
+ {
+ label: 'Requests',
+ data: [
+ { x: 0, y: 120 }, { x: 1, y: 180 }, { x: 2, y: 150 },
+ { x: 3, y: 210 }, { x: 4, y: 190 }, { x: 5, y: 240 },
+ ],
+ },
+ {
+ label: 'Errors',
+ data: [
+ { x: 0, y: 5 }, { x: 1, y: 12 }, { x: 2, y: 8 },
+ { x: 3, y: 15 }, { x: 4, y: 7 }, { x: 5, y: 10 },
+ ],
+ color: 'var(--error)',
+ },
+]
+
+const BAR_SERIES = [
+ {
+ label: 'GET',
+ data: [
+ { x: 'Mon', y: 80 }, { x: 'Tue', y: 95 }, { x: 'Wed', y: 110 },
+ { x: 'Thu', y: 72 }, { x: 'Fri', y: 130 },
+ ],
+ },
+ {
+ label: 'POST',
+ data: [
+ { x: 'Mon', y: 40 }, { x: 'Tue', y: 55 }, { x: 'Wed', y: 60 },
+ { x: 'Thu', y: 38 }, { x: 'Fri', y: 75 },
+ ],
+ color: 'var(--success)',
+ },
+]
+
+const COMMAND_PALETTE_DATA: SearchResult[] = [
+ { id: 'r1', category: 'route', title: 'order-ingest', meta: 'POST /orders/ingest' },
+ { id: 'r2', category: 'route', title: 'payment-validate', meta: 'POST /payments/validate' },
+ { id: 'e1', category: 'execution', title: 'exec-001', meta: 'Started 2m ago' },
+ { id: 'e2', category: 'execution', title: 'exec-002', meta: 'Completed 5m ago' },
+ { id: 'a1', category: 'agent', title: 'camel-agent-prod-1', meta: 'live · 42 tps' },
+ { id: 'x1', category: 'exchange', title: 'exch-aabb1122', meta: 'route: order-ingest' },
+]
+
+interface TableRow {
+ id: string
+ name: string
+ method: string
+ status: string
+ exchanges: number
+}
+
+const TABLE_DATA: TableRow[] = [
+ { id: '1', name: 'order-ingest', method: 'POST', status: 'live', exchanges: 1243 },
+ { id: '2', name: 'payment-validate', method: 'POST', status: 'live', exchanges: 987 },
+ { id: '3', name: 'inventory-check', method: 'GET', status: 'stale', exchanges: 432 },
+ { id: '4', name: 'notify-customer', method: 'POST', status: 'live', exchanges: 876 },
+ { id: '5', name: 'archive-order', method: 'PUT', status: 'dead', exchanges: 54 },
+]
+
+const NOW = new Date()
+const minsAgo = (n: number) => new Date(NOW.getTime() - n * 60 * 1000)
+
+const FEED_EVENTS = [
+ { id: 'ev1', severity: 'success' as const, message: 'Route order-ingest started successfully', timestamp: minsAgo(1) },
+ { id: 'ev2', severity: 'warning' as const, message: 'Agent camel-agent-prod-2 response time elevated', timestamp: minsAgo(3) },
+ { id: 'ev3', severity: 'error' as const, message: 'Exchange exch-aabb1122 failed: timeout', timestamp: minsAgo(7) },
+ { id: 'ev4', severity: 'running' as const, message: 'Processor payment-validate processing batch', timestamp: minsAgo(10) },
+ { id: 'ev5', severity: 'success' as const, message: 'Deployment v3.2.1 completed', timestamp: minsAgo(15) },
+]
+
+const TREE_NODES = [
+ {
+ id: 'app1',
+ label: 'cameleer-prod',
+ icon: '⬡',
+ children: [
+ {
+ id: 'route1',
+ label: 'order-ingest',
+ icon: '→',
+ children: [
+ { id: 'proc1', label: 'ValidateOrder', icon: '◈', meta: '12ms' },
+ { id: 'proc2', label: 'EnrichPayload', icon: '◈', meta: '8ms' },
+ { id: 'proc3', label: 'RouteToQueue', icon: '◈', meta: '3ms' },
+ ],
+ },
+ {
+ id: 'route2',
+ label: 'payment-validate',
+ icon: '→',
+ children: [
+ { id: 'proc4', label: 'TokenizeCard', icon: '◈', meta: '22ms' },
+ { id: 'proc5', label: 'AuthorizePayment', icon: '◈', meta: '45ms' },
+ ],
+ },
+ ],
+ },
+]
+
+// ── CompositesSection ─────────────────────────────────────────────────────────
+
+export function CompositesSection() {
+ // 1. Accordion
+ const accordionItems = [
+ { id: 'a1', title: 'What is Apache Camel?', content: 'Apache Camel is an open-source integration framework based on enterprise integration patterns.' },
+ { id: 'a2', title: 'How do routes work?', content: 'Routes define the path a message takes through the system, from consumer to producer.', defaultOpen: true },
+ { id: 'a3', title: 'What are processors?', content: 'Processors transform, filter, enrich, or route messages as they flow through a route.' },
+ ]
+
+ // 2. AlertDialog
+ const [alertOpen, setAlertOpen] = useState(false)
+ const [alertVariant, setAlertVariant] = useState<'danger' | 'warning' | 'info'>('danger')
+
+ // 7. CommandPalette
+ const [cmdOpen, setCmdOpen] = useState(false)
+
+ // 8. DataTable
+ const tableColumns = [
+ { key: 'name', header: 'Route', sortable: true },
+ { key: 'method', header: 'Method', sortable: true },
+ { key: 'status', header: 'Status', sortable: true },
+ { key: 'exchanges', header: 'Exchanges', sortable: true },
+ ]
+
+ // 9. DetailPanel
+ const [panelOpen, setPanelOpen] = useState(false)
+
+ // 12. FilterBar
+ const filterOptions = [
+ { label: 'Live', value: 'live', color: 'success' as const, count: 12 },
+ { label: 'Stale', value: 'stale', count: 3 },
+ { label: 'Dead', value: 'dead', color: 'error' as const, count: 1 },
+ ]
+ const [activeFilters, setActiveFilters] = useState([{ label: 'Live', value: 'live' }])
+
+ // 15. Modal
+ const [modalOpen, setModalOpen] = useState(false)
+
+ // 19. Tabs
+ const tabItems = [
+ { label: 'Overview', value: 'overview', count: undefined },
+ { label: 'Routes', value: 'routes', count: 14 },
+ { label: 'Agents', value: 'agents', count: 6 },
+ ]
+ const [activeTab, setActiveTab] = useState('overview')
+
+ // 21. TreeView
+ const [selectedNode, setSelectedNode] = useState('proc1')
+
+ return (
+
+
+ Composites
+
+ {/* 1. Accordion */}
+
+
+
Single mode (default)
+
+
Multiple mode
+
+
+
+
+ {/* 2. AlertDialog */}
+
+
+
+
+
+
+ setAlertOpen(false)}
+ onConfirm={() => setAlertOpen(false)}
+ title={alertVariant === 'danger' ? 'Delete route?' : alertVariant === 'warning' ? 'Proceed with caution?' : 'Confirm action'}
+ description={
+ alertVariant === 'danger'
+ ? 'This will permanently delete the route and all its exchange history. This action cannot be undone.'
+ : alertVariant === 'warning'
+ ? 'This operation will restart all active processors. Running exchanges may be interrupted.'
+ : 'This will update the route configuration and apply changes immediately.'
+ }
+ variant={alertVariant}
+ confirmLabel={alertVariant === 'danger' ? 'Delete' : 'Confirm'}
+ />
+
+
+ {/* 3. AreaChart */}
+
+
+
+
+ {/* 4. AvatarGroup */}
+
+
+
max=3, size=sm
+
+
max=4, size=md
+
+
max=2, size=lg
+
+
+
+
+ {/* 5. BarChart */}
+
+
+ Grouped
+
+ Stacked
+
+
+
+
+ {/* 6. Breadcrumb */}
+
+
+
+
+ {/* 7. CommandPalette */}
+
+
+ setCmdOpen(false)}
+ onSelect={() => setCmdOpen(false)}
+ data={COMMAND_PALETTE_DATA}
+ />
+
+
+ {/* 8. DataTable */}
+
+
+
+
+
+
+ {/* 9. DetailPanel */}
+
+
+ setPanelOpen(false)}
+ title="Route: order-ingest"
+ tabs={[
+ { label: 'Overview', value: 'overview', content: Route processes ~1,243 exchanges/day with avg latency 42ms.
},
+ { label: 'Processors', value: 'processors', content: ValidateOrder → EnrichPayload → RouteToQueue
},
+ { label: 'Errors', value: 'errors', content: 3 errors in last 24h. Last: timeout at EnrichPayload.
},
+ ]}
+ />
+
+
+ {/* 10. Dropdown */}
+
+ Actions ▾}
+ items={[
+ { label: 'View details', icon: '👁', onClick: () => undefined },
+ { label: 'Edit route', icon: '✏', onClick: () => undefined },
+ { divider: true, label: '' },
+ { label: 'Restart', icon: '↺', onClick: () => undefined },
+ { label: 'Delete', icon: '✕', onClick: () => undefined, disabled: true },
+ ]}
+ />
+
+
+ {/* 11. EventFeed */}
+
+
+
+
+
+
+ {/* 12. FilterBar */}
+
+
+
+
+
+
+ {/* 13. LineChart */}
+
+
+
+
+ {/* 14. MenuItem */}
+
+
+ {/* 15. Modal */}
+
+
+ setModalOpen(false)}
+ title="Configure Route"
+ size="md"
+ >
+
+
Adjust the route settings below. Changes will take effect immediately after saving.
+
Route: order-ingest · Processor chain: 3 steps · Avg latency: 42ms
+
+
+
+
+ {/* 16. Popover */}
+
+
+
Top}
+ content={Popover on top
}
+ />
+ Bottom}
+ content={Popover on bottom
}
+ />
+ Left}
+ content={Popover on left
}
+ />
+ Right}
+ content={Popover on right
}
+ />
+
+
+
+ {/* 17. ProcessorTimeline */}
+
+
+
+
+ {/* 18. ShortcutsBar */}
+
+
+
+
+ {/* 19. Tabs */}
+
+
+
+
+ Active tab: {activeTab}
+
+
+
+
+ {/* 20. Toast */}
+
+
+
+
+ {/* 21. TreeView */}
+
+
+
+
+
+ )
+}
diff --git a/src/pages/Inventory/sections/LayoutSection.module.css b/src/pages/Inventory/sections/LayoutSection.module.css
new file mode 100644
index 0000000..5f15c00
--- /dev/null
+++ b/src/pages/Inventory/sections/LayoutSection.module.css
@@ -0,0 +1,139 @@
+.section {
+ margin-bottom: 40px;
+}
+
+.sectionTitle {
+ font-size: 22px;
+ font-weight: 700;
+ color: var(--text-primary);
+ margin: 0 0 24px;
+}
+
+.componentCard {
+ background: var(--bg-surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ padding: 20px;
+ margin-bottom: 16px;
+ box-shadow: var(--shadow-sm);
+}
+
+.componentTitle {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 0 0 4px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.componentDesc {
+ font-size: 12px;
+ color: var(--text-muted);
+ margin: 0 0 16px;
+}
+
+.demoArea {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: flex-start;
+}
+
+.demoAreaColumn {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ align-items: flex-start;
+}
+
+.demoAreaRow {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: center;
+}
+
+.demoLabel {
+ font-size: 11px;
+ color: var(--text-muted);
+ font-weight: 500;
+}
+
+.demoGroup {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.demoGroupRow {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+/* AppShell diagram */
+.shellDiagram {
+ width: 100%;
+ background: var(--bg-canvas);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+ font-size: 11px;
+ color: var(--text-muted);
+}
+
+.shellDiagramTop {
+ border-bottom: 1px solid var(--border);
+ padding: 8px 12px;
+ background: var(--bg-overlay);
+ font-weight: 600;
+ color: var(--text-secondary);
+}
+
+.shellDiagramBody {
+ display: flex;
+ height: 140px;
+}
+
+.shellDiagramSide {
+ width: 140px;
+ border-right: 1px solid var(--border);
+ background: var(--bg-overlay);
+ padding: 8px 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ font-weight: 600;
+ color: var(--text-secondary);
+ flex-shrink: 0;
+}
+
+.shellDiagramMain {
+ flex: 1;
+ padding: 8px 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+/* Sidebar preview container */
+.sidebarPreview {
+ width: 220px;
+ height: 400px;
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ flex-shrink: 0;
+}
+
+/* TopBar preview container */
+.topbarPreview {
+ width: 100%;
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+}
diff --git a/src/pages/Inventory/sections/LayoutSection.tsx b/src/pages/Inventory/sections/LayoutSection.tsx
new file mode 100644
index 0000000..411a52a
--- /dev/null
+++ b/src/pages/Inventory/sections/LayoutSection.tsx
@@ -0,0 +1,140 @@
+import styles from './LayoutSection.module.css'
+import { Sidebar } from '../../../design-system/layout/Sidebar/Sidebar'
+import { TopBar } from '../../../design-system/layout/TopBar/TopBar'
+
+// ── DemoCard helper ──────────────────────────────────────────────────────────
+
+interface DemoCardProps {
+ id: string
+ title: string
+ description: string
+ children: React.ReactNode
+}
+
+function DemoCard({ id, title, description, children }: DemoCardProps) {
+ return (
+
+
{title}
+
{description}
+
{children}
+
+ )
+}
+
+// ── Sample data ───────────────────────────────────────────────────────────────
+
+const SAMPLE_APPS = [
+ { id: 'app1', name: 'cameleer-prod', agentCount: 3, health: 'live' as const, execCount: 14320 },
+ { id: 'app2', name: 'cameleer-staging', agentCount: 2, health: 'stale' as const, execCount: 871 },
+ { id: 'app3', name: 'cameleer-dev', agentCount: 1, health: 'dead' as const, execCount: 42 },
+]
+
+const SAMPLE_ROUTES = [
+ { id: 'r1', name: 'order-ingest', execCount: 5421 },
+ { id: 'r2', name: 'payment-validate', execCount: 3102 },
+ { id: 'r3', name: 'notify-customer', execCount: 2201 },
+]
+
+const SAMPLE_AGENTS = [
+ {
+ id: 'ag1',
+ name: 'agent-prod-1',
+ service: 'camel-core',
+ version: 'v3.2.1',
+ tps: '42 tps',
+ lastSeen: '1m ago',
+ status: 'live' as const,
+ },
+ {
+ id: 'ag2',
+ name: 'agent-prod-2',
+ service: 'camel-core',
+ version: 'v3.2.1',
+ tps: '38 tps',
+ lastSeen: '2m ago',
+ status: 'live' as const,
+ errorRate: '0.4%',
+ },
+ {
+ id: 'ag3',
+ name: 'agent-staging-1',
+ service: 'camel-core',
+ version: 'v3.1.9',
+ tps: '5 tps',
+ lastSeen: '8m ago',
+ status: 'stale' as const,
+ },
+]
+
+// ── LayoutSection ─────────────────────────────────────────────────────────────
+
+export function LayoutSection() {
+ return (
+
+ Layout
+
+ {/* 1. AppShell */}
+
+
+
+ TopBar — breadcrumb · search · env badge · shift · user avatar
+
+
+
+ Sidebar
+ Logo
+ Search
+ Navigation
+ Applications
+ Routes
+ Agents
+
+
+ <children> — page content rendered here
+
+
+
+
+
+ {/* 2. Sidebar */}
+
+
+ {/* 3. TopBar */}
+
+
+ undefined}
+ />
+
+
+
+ )
+}