| ... | @@ -144,6 +144,7 @@ import { | ... | @@ -144,6 +144,7 @@ import { |
| 144 | resolveSidebarThreadStatus, | 144 | resolveSidebarThreadStatus, |
| 145 | searchSidebarThreadsByTitle, | 145 | searchSidebarThreadsByTitle, |
| 146 | shouldCreateNewThreadInCurrentProject, | 146 | shouldCreateNewThreadInCurrentProject, |
| | 147 | shouldRecedeSidebarThread, |
| 147 | resolveWorkingStartedAt, | 148 | resolveWorkingStartedAt, |
| 148 | sortLogicalProjectsForSidebar, | 149 | sortLogicalProjectsForSidebar, |
| 149 | sortPinnedThreadsForSidebar, | 150 | sortPinnedThreadsForSidebar, |
| ... | @@ -874,6 +875,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -874,6 +875,8 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 874 | // switching sidebars must not light up every historical thread as unread. | 875 | // switching sidebars must not light up every historical thread as unread. |
| 875 | const isUnread = hasUnseenCompletion({ ...thread, lastVisitedAt }); | 876 | const isUnread = hasUnseenCompletion({ ...thread, lastVisitedAt }); |
| 876 | const status = resolveSidebarThreadStatus(thread); | 877 | const status = resolveSidebarThreadStatus(thread); |
| | 878 | const isInFlight = |
| | 879 | status === "working" || status === "monitoring" || status === "approval" || status === "input"; |
| 877 | // A woken thread reappears at its original position (the sort is | 880 | // A woken thread reappears at its original position (the sort is |
| 878 | // deliberately static), so the pill has to carry the weight. Snoozing is | 881 | // deliberately static), so the pill has to carry the weight. Snoozing is |
| 879 | // an explicit act, so the pill clears only when the user re-engages: | 882 | // an explicit act, so the pill clears only when the user re-engages: |
| ... | @@ -887,17 +890,16 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -887,17 +890,16 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 887 | wokeAtDate !== null && | 890 | wokeAtDate !== null && |
| 888 | (lastVisitedDate === null || lastVisitedDate < wokeAtDate) && | 891 | (lastVisitedDate === null || lastVisitedDate < wokeAtDate) && |
| 889 | thread.settledOverride !== "settled"; | 892 | thread.settledOverride !== "settled"; |
| 890 | // In-flight rows (working, or waiting on approval/input) fade as a whole: | 893 | // Background work always recedes when it is not selected: an unread parent |
| 891 | // there is nothing for the user to do yet, so prominence is reserved for | 894 | // completion must not pull a still-working thread back into the foreground. |
| 892 | // rows that need a human — done (unread), read-but-unsettled, failed, and | 895 | // Ready and action-required rows keep their unread and wake prominence. |
| 893 | // freshly woken. The status label keeps its hue, so waiting rows stay | 896 | const shouldRecede = shouldRecedeSidebarThread({ |
| 894 | // findable. In-flight rows recede the same as read-ready ones (inbox-zero: | 897 | status, |
| 895 | // working threads aren't your problem yet) — only the colored status label | 898 | isUnread, |
| 896 | // stands out. | 899 | isWoke, |
| 897 | const isInFlight = | 900 | isActive: props.isActive, |
| 898 | status === "working" || status === "monitoring" || status === "approval" || status === "input"; | 901 | isSelected, |
| 899 | const shouldRecede = | 902 | }); |
| 900 | (status === "ready" || isInFlight) && !isUnread && !isWoke && !props.isActive && !isSelected; | | |
| 901 | // Status hues follow the system-wide convention set by sidebar v1 and the | 903 | // Status hues follow the system-wide convention set by sidebar v1 and the |
| 902 | // mobile Live Activity/widgets (amber approval, indigo input, sky working) | 904 | // mobile Live Activity/widgets (amber approval, indigo input, sky working) |
| 903 | // so a thread reads the same color everywhere it surfaces. | 905 | // so a thread reads the same color everywhere it surfaces. |
| ... | @@ -1210,21 +1212,23 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { | ... | @@ -1210,21 +1212,23 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { |
| 1210 | variant === "card" | 1212 | variant === "card" |
| 1211 | ? cn( | 1213 | ? cn( |
| 1212 | "truncate", | 1214 | "truncate", |
| 1213 | isUnread || isWoke | 1215 | shouldRecede |
| 1214 | ? "text-foreground" | 1216 | ? "text-secondary-label" |
| 1215 | : shouldRecede | 1217 | : isUnread || isWoke |
| 1216 | ? "text-secondary-label" | 1218 | ? "text-foreground" |
| 1217 | : status === "failed" | 1219 | : status === "failed" |
| 1218 | ? "text-foreground/95" | 1220 | ? "text-foreground/95" |
| 1219 | : "text-foreground/90", | 1221 | : "text-foreground/90", |
| 1220 | ) | 1222 | ) |
| 1221 | : cn( | 1223 | : cn( |
| 1222 | "truncate group-hover/sidebar-row:text-foreground", | 1224 | "truncate group-hover/sidebar-row:text-foreground", |
| 1223 | props.isActive || isWoke | 1225 | shouldRecede |
| 1224 | ? "text-foreground" | 1226 | ? "text-secondary-label/70" |
| 1225 | : isUnread | 1227 | : props.isActive || isWoke |
| 1226 | ? "text-muted-foreground" | 1228 | ? "text-foreground" |
| 1227 | : "text-secondary-label/70", | 1229 | : isUnread |
| | 1230 | ? "text-muted-foreground" |
| | 1231 | : "text-secondary-label/70", |
| 1228 | ), | 1232 | ), |
| 1229 | isRegeneratingTitle && "opacity-[0.55]", | 1233 | isRegeneratingTitle && "opacity-[0.55]", |
| 1230 | )} | 1234 | )} |