From 838663cfc260f4986d6a74557438291f018669df Mon Sep 17 00:00:00 2001 From: Brad Groux <3053586+BradGroux@users.noreply.github.com> Date: Sun, 30 Aug 2026 02:52:25 -0500 Subject: [PATCH] fix: constrain shared interface motion --- .../dashboard-motion-contract.test.tsx | 38 +++++++++++++++++++ web/src/components/board/BoardSidebar.tsx | 6 +-- web/src/components/board/KanbanColumn.tsx | 2 +- web/src/components/board/MultiAgentPanel.tsx | 7 +--- web/src/components/chat/FloatingChat.tsx | 7 ++-- web/src/components/layout/ActivitySidebar.tsx | 15 ++------ web/src/components/task/AgentPanel.tsx | 2 +- .../components/task/MultiAgentSelector.tsx | 11 ++---- web/src/components/task/TaskCard.tsx | 8 ++-- .../components/task/TimeTrackingSection.tsx | 4 +- .../components/templates/TemplatesPage.tsx | 2 +- web/src/components/ui/badge.tsx | 2 +- web/src/components/ui/button.tsx | 2 +- web/src/components/ui/switch.tsx | 2 +- web/src/components/ui/tabs.tsx | 2 +- 15 files changed, 66 insertions(+), 44 deletions(-) diff --git a/web/src/__tests__/dashboard-motion-contract.test.tsx b/web/src/__tests__/dashboard-motion-contract.test.tsx index 85c18dac..a72dbf8e 100644 --- a/web/src/__tests__/dashboard-motion-contract.test.tsx +++ b/web/src/__tests__/dashboard-motion-contract.test.tsx @@ -12,12 +12,33 @@ vi.mock('@/components/dashboard/Dashboard', () => ({ const motionSources = [ 'components/activity/ActivityFeed.tsx', + 'components/board/BoardSidebar.tsx', + 'components/board/KanbanColumn.tsx', + 'components/board/MultiAgentPanel.tsx', + 'components/chat/FloatingChat.tsx', 'components/dashboard/Dashboard.tsx', 'components/dashboard/DashboardPage.tsx', 'components/dashboard/DashboardSection.tsx', 'components/dashboard/HourlyActivityChart.tsx', 'components/dashboard/StatusTimeline.tsx', 'components/dashboard/WhereTimeWent.tsx', + 'components/layout/ActivitySidebar.tsx', + 'components/task/MultiAgentSelector.tsx', + 'components/task/TaskCard.tsx', + 'components/templates/TemplatesPage.tsx', + 'components/ui/badge.tsx', + 'components/ui/button.tsx', + 'components/ui/switch.tsx', + 'components/ui/tabs.tsx', +]; + +const stableStatusSources = [ + 'components/board/BoardSidebar.tsx', + 'components/board/MultiAgentPanel.tsx', + 'components/chat/FloatingChat.tsx', + 'components/task/AgentPanel.tsx', + 'components/task/TaskCard.tsx', + 'components/task/TimeTrackingSection.tsx', ]; const storage = new Map(); @@ -53,6 +74,23 @@ describe('dashboard motion contract', () => { } }); + it('keeps persistent live and unread status treatments stable', () => { + for (const file of stableStatusSources) { + const source = readFileSync(resolve(process.cwd(), 'src', file), 'utf8'); + + expect(source, file).not.toContain('animate-ping'); + expect(source, file).not.toContain('animate-pulse'); + expect(source, file).not.toMatch(/hover:(?:scale|translate)/); + } + + const taskCard = readFileSync( + resolve(process.cwd(), 'src/components/task/TaskCard.tsx'), + 'utf8' + ); + expect(taskCard).toContain('motion-safe:rotate-2'); + expect(taskCard).toContain('motion-safe:scale-105'); + }); + it('expands and collapses immediately with explicit accessible state', async () => { const user = userEvent.setup(); renderWithProviders(); diff --git a/web/src/components/board/BoardSidebar.tsx b/web/src/components/board/BoardSidebar.tsx index e7b24517..04b609fa 100644 --- a/web/src/components/board/BoardSidebar.tsx +++ b/web/src/components/board/BoardSidebar.tsx @@ -174,7 +174,7 @@ function AgentStatusPanel({ onTaskClick }: { onTaskClick?: (taskId: string) => v {/* Status header — large icon + state */}
@@ -186,7 +186,7 @@ function AgentStatusPanel({ onTaskClick }: { onTaskClick?: (taskId: string) => v > {state !== 'idle' && ( )} @@ -226,7 +226,7 @@ function AgentStatusPanel({ onTaskClick }: { onTaskClick?: (taskId: string) => v onClick={() => agent.taskId && onTaskClick?.(agent.taskId)} >
diff --git a/web/src/components/board/KanbanColumn.tsx b/web/src/components/board/KanbanColumn.tsx index a0dccd03..0e59b7e9 100644 --- a/web/src/components/board/KanbanColumn.tsx +++ b/web/src/components/board/KanbanColumn.tsx @@ -75,7 +75,7 @@ export function KanbanColumn({ aria-labelledby={`column-heading-${id}`} aria-roledescription="kanban column" className={cn( - 'flex flex-col rounded-lg bg-muted/50 border-t-2 transition-all', + 'flex flex-col rounded-lg bg-muted/50 border-t-2 transition-colors', columnColors[id] ?? 'border-t-primary', dragEnabled && isOver && 'ring-2 ring-primary/50 bg-muted/70' )} diff --git a/web/src/components/board/MultiAgentPanel.tsx b/web/src/components/board/MultiAgentPanel.tsx index d413aa0d..9c1568e8 100644 --- a/web/src/components/board/MultiAgentPanel.tsx +++ b/web/src/components/board/MultiAgentPanel.tsx @@ -60,7 +60,7 @@ function AgentCard({ return (
{/* Header */} @@ -69,10 +69,7 @@ function AgentCard({ onClick={() => setExpanded(!expanded)} > {/* Status dot */} - + {/* Name + model */}
diff --git a/web/src/components/chat/FloatingChat.tsx b/web/src/components/chat/FloatingChat.tsx index 1ecf0368..27421fa7 100644 --- a/web/src/components/chat/FloatingChat.tsx +++ b/web/src/components/chat/FloatingChat.tsx @@ -58,16 +58,15 @@ export function FloatingChat() { className={cn( 'floating-chat-trigger z-40 h-14 w-14 rounded-full shadow-lg', 'bg-primary hover:bg-primary/90 text-primary-foreground', - 'transition-all duration-200 hover:scale-105', + 'transition-colors duration-150', open && 'hidden' )} aria-label="Open chat" > {hasUnread && ( - - - +