diff --git a/packages/app/src/components/workspace-hover-card.tsx b/packages/app/src/components/workspace-hover-card.tsx index 74cf0c9471..c01e929449 100644 --- a/packages/app/src/components/workspace-hover-card.tsx +++ b/packages/app/src/components/workspace-hover-card.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, + useMemo, useRef, useState, type PropsWithChildren, @@ -248,6 +249,19 @@ function WorkspaceHoverCardContent({ [], ); + const cardStyle = useMemo( + () => [ + styles.card, + { + width: HOVER_CARD_WIDTH, + position: "absolute" as const, + top: position?.y ?? -9999, + left: position?.x ?? -9999, + }, + ], + [position?.x, position?.y], + ); + return ( @@ -260,15 +274,7 @@ function WorkspaceHoverCardContent({ accessibilityRole="menu" accessibilityLabel="Workspace scripts" testID="workspace-hover-card" - style={[ - styles.card, - { - width: HOVER_CARD_WIDTH, - position: "absolute", - top: position?.y ?? -9999, - left: position?.x ?? -9999, - }, - ]} + style={cardStyle} > @@ -298,6 +304,62 @@ function WorkspaceHoverCardContent({ ); } +function ChecksSummaryContent({ + checks, + theme, + hovered, +}: { + checks: NonNullable; + theme: ReturnType["theme"]; + hovered: boolean; +}) { + const failed = checks.filter((c) => c.status === "failure").length; + const pending = checks.filter((c) => c.status === "pending").length; + + let badgeColor: string; + let badgeLabel: string; + + if (failed > 0) { + badgeColor = theme.colors.palette.red[500]; + badgeLabel = `${failed} failed`; + } else if (pending > 0) { + badgeColor = theme.colors.palette.amber[500]; + badgeLabel = `${pending} running`; + } else { + badgeColor = theme.colors.palette.green[500]; + badgeLabel = `${checks.length} passed`; + } + + const iconColor = hovered ? theme.colors.foreground : theme.colors.foregroundMuted; + const labelStyle = useMemo( + () => [styles.checksSummaryLabel, hovered && styles.checksSummaryLabelHovered], + [hovered], + ); + const dotStyle = useMemo( + () => [styles.checksDot, { backgroundColor: badgeColor }], + [badgeColor], + ); + const statusTextStyle = useMemo( + () => [styles.checksStatusText, { color: badgeColor }], + [badgeColor], + ); + + return ( + <> + {hovered ? ( + + ) : ( + + )} + Checks + + + {badgeLabel} + + + ); +} + function ChecksSummaryPressable({ checks, url, @@ -320,47 +382,9 @@ function ChecksSummaryPressable({ ); const renderChildren = useCallback( - ({ hovered }: { pressed: boolean; hovered?: boolean }) => { - const failed = checks.filter((c) => c.status === "failure").length; - const pending = checks.filter((c) => c.status === "pending").length; - - let badgeColor: string; - let badgeLabel: string; - - if (failed > 0) { - badgeColor = theme.colors.palette.red[500]; - badgeLabel = `${failed} failed`; - } else if (pending > 0) { - badgeColor = theme.colors.palette.amber[500]; - badgeLabel = `${pending} running`; - } else { - badgeColor = theme.colors.palette.green[500]; - badgeLabel = `${checks.length} passed`; - } - - const iconColor = hovered ? theme.colors.foreground : theme.colors.foregroundMuted; - return ( - <> - {hovered ? ( - - ) : ( - - )} - - Checks - - - - {badgeLabel} - - - ); - }, + ({ hovered }: { pressed: boolean; hovered?: boolean }) => ( + + ), [checks, theme], );