Files
Codewalkers/apps/web/src/components/MessageCard.tsx
Lukas May 04c212da92 feat: Implement v2 design system with indigo brand, dark mode, and status tokens
Complete frontend design overhaul replacing achromatic shadcn/ui defaults with
an indigo-branded (#6366F1), status-aware, dark-mode-enabled token system.

Phase 1 — Theme Foundation:
- Replace all CSS tokens in index.css with v2 light/dark mode values
- Add 24 status tokens (6 statuses × 4 variants), 22 terminal tokens,
  7 diff tokens, 5 shadow tokens, 9 transition/animation tokens,
  10 z-index tokens, 10-step extended indigo scale
- Install Geist Sans/Mono variable fonts (public/fonts/)
- Extend tailwind.config.ts with all new token utilities
- Add dark mode flash-prevention script in index.html
- Add status-pulse and shimmer keyframe animations
- Add global focus-visible styles and reduced-motion media query

Phase 2 — ThemeProvider + Toggle:
- ThemeProvider context with system preference listener
- 3-state ThemeToggle (Sun/Monitor/Moon)
- Radix tooltip primitive for tooltips
- localStorage persistence with 'cw-theme' key

Phase 3 — Shared Components + Token Migration:
- StatusDot: mapEntityStatus() maps raw statuses to 6 semantic variants
- StatusBadge: uses status token bg/fg/border classes
- Badge: 6 new status variants + xs size
- EmptyState, ErrorState, SaveIndicator shared patterns
- CommandPalette: Cmd+K search with fuzzy matching, keyboard nav
- Skeleton with shimmer animation + SkeletonCard composite layouts
- KeyboardShortcutHint, NavBadge, enhanced Sonner config
- Migrate ALL hardcoded Tailwind colors to token classes across
  AgentOutputViewer, review/*, ProgressBar, AccountCard,
  InitiativeHeader, DependencyIndicator, PipelineTaskCard,
  PreviewPanel, ChangeSetBanner, MessageCard, PhaseDetailPanel

Phase 4 — App Layout Overhaul:
- Single 48px row header with CW logo, nav with NavBadge counts,
  Cmd+K search button, ThemeToggle, HealthDot
- Remove max-w-7xl from header/main; pages control own widths
- ConnectionBanner for offline/reconnecting states
- BrowserTitleUpdater with running/questions counts
- useGlobalKeyboard (1-4 nav, Cmd+K), useConnectionStatus hooks
- Per-page width wrappers (initiatives max-w-6xl, settings max-w-4xl)

Phase 5 — Page-Level Token Migration:
- ReviewSidebar: all hardcoded green/orange/red → status/diff tokens
- CommentThread: resolved state → status-success tokens
- Settings health: green → status-success-dot
2026-03-03 11:43:09 +01:00

69 lines
1.8 KiB
TypeScript

import { Card } from "@/components/ui/card";
import { cn, formatRelativeTime } from "@/lib/utils";
interface MessageCardProps {
agentName: string;
agentStatus: string;
preview: string;
timestamp: string;
requiresResponse: boolean;
isSelected: boolean;
onClick: () => void;
}
function formatStatusLabel(status: string): string {
return status.replace(/_/g, " ");
}
function truncatePreview(text: string, maxLength = 80): string {
if (text.length <= maxLength) return text;
return text.slice(0, maxLength) + "...";
}
export function MessageCard({
agentName,
agentStatus,
preview,
timestamp,
requiresResponse,
isSelected,
onClick,
}: MessageCardProps) {
return (
<Card
className={cn(
"cursor-pointer p-4 transition-colors hover:bg-accent/50",
isSelected && "bg-accent",
)}
onClick={onClick}
>
<div className="flex items-start justify-between gap-4">
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<span
className={cn(
"text-sm",
requiresResponse ? "text-status-warning-dot" : "text-muted-foreground",
)}
>
{requiresResponse ? "\u25CF" : "\u25CB"}
</span>
<span className="text-sm font-bold">
{agentName}{" "}
<span className="font-normal text-muted-foreground">
({formatStatusLabel(agentStatus)})
</span>
</span>
</div>
<p className="mt-1 pl-5 text-sm text-muted-foreground">
&ldquo;{truncatePreview(preview)}&rdquo;
</p>
</div>
<span className="shrink-0 text-xs text-muted-foreground">
{formatRelativeTime(timestamp)}
</span>
</div>
</Card>
);
}