mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(conversations): stop the thread-goal footer text from auto-scrolling (#5030)
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user