fix(conversations): stop the thread-goal footer text from auto-scrolling (#5030)

This commit is contained in:
James Gentes
2026-07-21 19:59:50 +03:00
committed by GitHub
parent 7ec16e8def
commit 78949de1de
2 changed files with 6 additions and 47 deletions
@@ -213,7 +213,12 @@ export function ThreadGoalFooterTrigger({
className={`shrink-0 rounded px-1 py-0.5 text-[10px] font-medium uppercase tracking-wide ${statusClasses(ctl.goal.status)}`}>
{t(`conversations.threadGoal.status.${ctl.goal.status}`)}
</span>
<MarqueeText text={ctl.goal.objective} className="max-w-[18rem] text-content-secondary" />
{/* Truncate long objectives instead of scrolling them. The full text is
reachable via the button's `title` tooltip (hover) and by clicking to
open the editor, so a moving label would only distract. */}
<span className="block min-w-0 max-w-[18rem] truncate text-content-secondary">
{ctl.goal.objective}
</span>
</button>
);
}
@@ -305,44 +310,6 @@ export function ThreadGoalEditorPanel({
);
}
/**
* Single-line label that gently marquees (ping-pong scroll) only when the text
* overflows its max width; otherwise it truncates. The scroll distance is
* measured and fed to the `goal-marquee` keyframe via a CSS variable.
*/
function MarqueeText({
text,
className = '',
}: {
text: string;
className?: string;
}): React.ReactElement {
const outerRef = useRef<HTMLSpanElement>(null);
const innerRef = useRef<HTMLSpanElement>(null);
const [shift, setShift] = useState(0);
useEffect(() => {
const outer = outerRef.current;
const inner = innerRef.current;
if (!outer || !inner) return;
const overflow = inner.scrollWidth - outer.clientWidth;
setShift(overflow > 4 ? overflow + 8 : 0);
}, [text]);
return (
<span ref={outerRef} className={`relative block min-w-0 overflow-hidden ${className}`}>
<span
ref={innerRef}
className={`block whitespace-nowrap ${shift > 0 ? 'animate-goal-marquee' : 'truncate'}`}
style={
shift > 0 ? ({ '--goal-marquee-shift': `-${shift}px` } as React.CSSProperties) : undefined
}>
{text}
</span>
</span>
);
}
function PanelButton({
label,
onClick,
-8
View File
@@ -271,10 +271,6 @@ module.exports = {
'float': 'float 3s ease-in-out infinite',
'ticker': 'ticker 30s linear infinite',
'wiggle': 'wiggle 0.5s ease-in-out',
// Gentle ping-pong scroll for overflowing single-line labels (e.g. a
// long thread-goal objective). Distance is supplied per-element via the
// `--goal-marquee-shift` CSS var; `alternate` returns it to the start.
'goal-marquee': 'goalMarquee 6s ease-in-out infinite alternate',
},
keyframes: {
@@ -319,10 +315,6 @@ module.exports = {
'25%': { transform: 'rotate(-9deg)' },
'75%': { transform: 'rotate(9deg)' },
},
goalMarquee: {
'0%, 18%': { transform: 'translateX(0)' },
'82%, 100%': { transform: 'translateX(var(--goal-marquee-shift, 0px))' },
},
},
// Backdrop blur for glass morphism