fix: pause task ticker in hidden tabs

This commit is contained in:
2026-07-22 11:38:51 +08:00
parent 5ee469ff5b
commit d2c278f0ea
2 changed files with 121 additions and 6 deletions
@@ -101,6 +101,10 @@ export function AgentTaskTicker({
active: false
}));
const [isHovered, setIsHovered] = useState(false);
const [isDocumentVisible, setIsDocumentVisible] = useState(() => (
typeof document === "undefined" || document.visibilityState === "visible"
));
const [visibilityRevision, setVisibilityRevision] = useState(0);
const runningConditions = conditions;
const visibleTickerCards = useMemo(
() => createVisibleTickerCards(runningConditions, rotationIndex, nowMs),
@@ -181,13 +185,19 @@ export function AgentTaskTicker({
}, [hasMultipleRunningTasks, showNextTask, showPreviousTask]);
useEffect(() => {
setNowMs(Date.now());
if (!isDocumentVisible) {
return;
}
const refreshNow = () => setNowMs(Date.now());
refreshNow();
const intervalId = window.setInterval(() => {
setNowMs(Date.now());
refreshNow();
}, 1_000);
return () => window.clearInterval(intervalId);
}, []);
}, [isDocumentVisible]);
useEffect(() => {
setRotationIndex(0);
@@ -197,6 +207,26 @@ export function AgentTaskTicker({
useEffect(() => releaseTaskSwitchLock, [releaseTaskSwitchLock]);
useEffect(() => {
const handleVisibilityChange = () => {
const isVisible = document.visibilityState === "visible";
releaseTaskSwitchLock();
finishTaskSwitchAnimation();
setIsHovered(false);
setIsDocumentVisible(isVisible);
setVisibilityRevision((current) => current + 1);
if (isVisible) {
setNowMs(Date.now());
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => document.removeEventListener("visibilitychange", handleVisibilityChange);
}, [finishTaskSwitchAnimation, releaseTaskSwitchLock]);
useEffect(() => {
const section = sectionRef.current;
if (!section) {
@@ -209,16 +239,20 @@ export function AgentTaskTicker({
}, [handleWheel]);
useEffect(() => {
if (!hasMultipleRunningTasks || isHovered) {
if (!hasMultipleRunningTasks || isHovered || !isDocumentVisible) {
return;
}
const intervalId = window.setInterval(() => {
if (document.visibilityState !== "visible") {
return;
}
shiftTask(1);
}, 6_000);
return () => window.clearInterval(intervalId);
}, [hasMultipleRunningTasks, isHovered, runningConditions.length, shiftTask]);
}, [hasMultipleRunningTasks, isDocumentVisible, isHovered, runningConditions.length, shiftTask]);
if (visibleTickerCards.length === 0) {
return null;
@@ -237,7 +271,12 @@ export function AgentTaskTicker({
onMouseLeave={() => setIsHovered(false)}
>
<div className="absolute inset-0">
<AnimatePresence custom={transitionDirection} mode="popLayout" initial={false}>
<AnimatePresence
key={`ticker-presence-${visibilityRevision}`}
custom={transitionDirection}
mode="popLayout"
initial={false}
>
{visibleTickerCards
.slice()
.reverse()
@@ -320,6 +359,7 @@ function TickerTaskCard({
}}
exit="exit"
aria-hidden={!isActive}
data-condition-id={condition.id}
>
<div
className={cn(