feat(app): add running status ring and lighten status dots

Keep the animated ring phase-locked across hosts and derive its knockout surface from each host's actual interaction state. Align filled status circles at 6px while preserving the larger needs-input alert.

Co-authored-by: Christoph Leiter <christoph@leiter.io>
This commit is contained in:
Mohamed Boudra
2026-08-09 11:33:58 +02:00
co-authored by Christoph Leiter
parent 6ae6231d1f
commit c0daf8e066
23 changed files with 584 additions and 153 deletions
@@ -175,6 +175,7 @@ import {
import { findAdjacentPane } from "@/utils/split-navigation";
import { useIsCompactFormFactor, supportsDesktopPaneSplits } from "@/constants/layout";
import { getIsElectron, isNative, isWeb } from "@/constants/platform";
import type { SurfaceBackdrop } from "@/styles/surface-backdrop";
import { useContainerWidthBelow } from "@/hooks/use-container-width";
import {
buildHostRootRoute,
@@ -429,10 +430,12 @@ function MobileActiveTabTrigger({
activeTab,
normalizedServerId,
normalizedWorkspaceId,
backdrop,
}: {
activeTab: WorkspaceTabDescriptor | null;
normalizedServerId: string;
normalizedWorkspaceId: string;
backdrop: SurfaceBackdrop;
}) {
if (!activeTab) {
return null;
@@ -443,6 +446,7 @@ function MobileActiveTabTrigger({
activeTab={activeTab}
normalizedServerId={normalizedServerId}
normalizedWorkspaceId={normalizedWorkspaceId}
backdrop={backdrop}
/>
);
}
@@ -451,10 +455,12 @@ function ResolvedMobileActiveTabTrigger({
activeTab,
normalizedServerId,
normalizedWorkspaceId,
backdrop,
}: {
activeTab: WorkspaceTabDescriptor;
normalizedServerId: string;
normalizedWorkspaceId: string;
backdrop: SurfaceBackdrop;
}) {
const { t } = useTranslation();
return (
@@ -466,7 +472,7 @@ function ResolvedMobileActiveTabTrigger({
{(presentation) => (
<>
<View style={styles.switcherTriggerIcon} testID="workspace-active-tab-icon">
<WorkspaceTabIcon presentation={presentation} active />
<WorkspaceTabIcon presentation={presentation} active backdrop={backdrop} />
</View>
<Text style={styles.switcherTriggerText} numberOfLines={1}>
@@ -741,14 +747,19 @@ const MobileWorkspaceTabSwitcher = memo(function MobileWorkspaceTabSwitcher({
style={switcherTriggerStyle}
onPress={handleOpenSwitcher}
>
<View style={styles.switcherTriggerLeft}>
<MobileActiveTabTrigger
activeTab={activeTab}
normalizedServerId={normalizedServerId}
normalizedWorkspaceId={normalizedWorkspaceId}
/>
</View>
<ThemedChevronDown size={14} uniProps={mutedColorMapping} />
{({ pressed }) => (
<>
<View style={styles.switcherTriggerLeft}>
<MobileActiveTabTrigger
activeTab={activeTab}
normalizedServerId={normalizedServerId}
normalizedWorkspaceId={normalizedWorkspaceId}
backdrop={pressed ? "surface1" : "surface0"}
/>
</View>
<ThemedChevronDown size={14} uniProps={mutedColorMapping} />
</>
)}
</Pressable>
<Combobox