- Add ComparePane.tsx: side-by-side AI response comparison - Add Memory.tsx: memory management page with CRUD UI - Add McpPermissionDialog.tsx: MCP tool permission approval dialog - Add McpResponseDisplay.tsx: MCP response visualization - Add MessageBoundary.tsx + MessageListErrorBoundary.tsx: error resilience - Add EmptyState.tsx: contextual empty state component - Add KeyboardShortcutsDialog.tsx: keyboard shortcut reference - Add message-parts/: ActionRow, CompactCard, MistakeRecoverySentinel, ReasoningBlock, SendToTerminalMenu, StatsLine, SummaryCard - Add useDraftPersistence.ts: draft message persistence hook - Add useTerminals.ts: terminal session management hook - Add keyboard-shortcuts.ts + tool-utils.ts: shared utilities - Extend components: ChatInput, MessageBubble, MessageList, Workspace, panes - Extend hooks: useTerminalSocket, useSessionStream test suite - Update pages: Home, Project — workspace layout and session flow
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { Inbox } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface EmptyStateProps {
|
|
/** Optional icon node shown above the title. Defaults to a muted Inbox icon. */
|
|
icon?: ReactNode;
|
|
/** Main heading text (bold, base font-size). */
|
|
title: string;
|
|
/** Optional descriptive text shown below the title (muted, sm font-size). */
|
|
description?: string;
|
|
/** Optional CTA button rendered below the description. */
|
|
action?: {
|
|
label: string;
|
|
onClick: () => void;
|
|
variant?: 'default' | 'outline';
|
|
};
|
|
className?: string;
|
|
}
|
|
|
|
/**
|
|
* Reusable empty state for lists, search results, and landing pages.
|
|
*
|
|
* Renders a centered column with:
|
|
* 1. Optional icon (default: `Inbox` from lucide-react, drawn at 50% muted
|
|
* opacity so it sits subtly in the background).
|
|
* 2. Bold title.
|
|
* 3. Optional description (constrained to `max-w-sm` for readability).
|
|
* 4. Optional action button (outline by default).
|
|
*
|
|
* Design follows The Data Terminal aesthetic: charcoal canvas, low-chrome
|
|
* muted icon, high-contrast text, and an outline button that gets an ember
|
|
* glow on interaction.
|
|
*/
|
|
export function EmptyState({
|
|
icon,
|
|
title,
|
|
description,
|
|
action,
|
|
className,
|
|
}: EmptyStateProps) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex flex-col items-center justify-center text-center gap-3 px-4 py-12',
|
|
className,
|
|
)}
|
|
>
|
|
<div className="text-muted-foreground/50">
|
|
{icon ?? <Inbox size={40} strokeWidth={1.5} />}
|
|
</div>
|
|
<h3 className="text-base font-semibold text-foreground">{title}</h3>
|
|
{description && (
|
|
<p className="text-sm text-muted-foreground max-w-sm">{description}</p>
|
|
)}
|
|
{action && (
|
|
<Button
|
|
variant={action.variant ?? 'outline'}
|
|
onClick={action.onClick}
|
|
className="mt-1"
|
|
>
|
|
{action.label}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|