From 6523a5add65ab109ae671c1c37a67c0554c77305 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Tue, 30 Jun 2026 16:49:01 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=BA=EF=B8=8F=20refactor:=20Light=20Up?= =?UTF-8?q?=20In-Viewport=20Ribs=20at=20Rest=20in=20Message=20Nav=20(#1404?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At rest (no hover/focus) the rail now reads like a minimap: only the in-viewport message ribs are at full opacity while the rest fade to 40%, updating live as you scroll. Replaces the blanket nav opacity-30 with per-rib opacity driven by the existing viewport-visibility highlight, so hover/focus still brings every rib to full opacity for the fisheye. --- .../components/Chat/Messages/MessageNav.tsx | 14 +++++++------ .../Messages/__tests__/MessageNav.spec.tsx | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/client/src/components/Chat/Messages/MessageNav.tsx b/client/src/components/Chat/Messages/MessageNav.tsx index a6545420a0..2112bee670 100644 --- a/client/src/components/Chat/Messages/MessageNav.tsx +++ b/client/src/components/Chat/Messages/MessageNav.tsx @@ -130,10 +130,13 @@ export function magnifyFalloff(distance: number, influence: number): number { } const indicatorButtonClasses = cn( - 'flex h-1.5 w-full items-center justify-end rounded-sm', + 'flex h-1.5 w-full items-center justify-end rounded-sm transition-opacity duration-300', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-xheavy', ); +const dimIndicatorClasses = + 'opacity-40 group-hover/nav:opacity-100 group-focus-within/nav:opacity-100'; + const MessageIndicator = memo(function MessageIndicator({ entry, isHighlighted, @@ -155,7 +158,7 @@ const MessageIndicator = memo(function MessageIndicator({ e.stopPropagation(); onSelect(entry.id); }} - className={indicatorButtonClasses} + className={cn(indicatorButtonClasses, isHighlighted ? 'opacity-100' : dimIndicatorClasses)} aria-label={label} aria-current={isCurrent ? 'true' : undefined} data-msg-id={entry.id} @@ -172,8 +175,9 @@ const MessageIndicator = memo(function MessageIndicator({ }); const chevronButtonClasses = cn( - 'rounded-md p-0.5 text-text-tertiary transition-colors', - 'group-hover/nav:text-text-secondary group-focus-within/nav:text-text-secondary', + 'rounded-md p-0.5 text-text-tertiary opacity-40 transition-[color,opacity] duration-300', + 'group-hover/nav:text-text-secondary group-hover/nav:opacity-100', + 'group-focus-within/nav:text-text-secondary group-focus-within/nav:opacity-100', 'group-hover/nav:hover:text-text-primary', 'group-hover/nav:disabled:opacity-30 group-focus-within/nav:disabled:opacity-30', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-xheavy', @@ -1113,8 +1117,6 @@ function MessageNav({ scrollableRef }: { scrollableRef: React.RefObject