diff --git a/packages/app/src/components/agent-list.tsx b/packages/app/src/components/agent-list.tsx
index e2bcafa1f..f9a8a2318 100644
--- a/packages/app/src/components/agent-list.tsx
+++ b/packages/app/src/components/agent-list.tsx
@@ -215,6 +215,11 @@ function SessionRow({
[isSelected],
);
+ const archivedIcon = useMemo(
+ () => ,
+ [theme.fontSize.xs, theme.colors.foregroundMuted],
+ );
+
return (
{agent.title || "New session"}
- {agent.archivedAt ? (
- }
- />
- ) : null}
+ {agent.archivedAt ? : null}
{(agent.pendingPermissionCount ?? 0) > 0 ? (
) : null}
@@ -428,6 +428,19 @@ export function AgentList({
[isActionDaemonUnavailable],
);
+ const refreshControl = useMemo(
+ () =>
+ onRefresh ? (
+
+ ) : undefined,
+ [onRefresh, isRefreshing, theme.colors.foregroundMuted, refreshColors],
+ );
+
return (
<>
- ) : undefined
- }
+ refreshControl={refreshControl}
/>
void;
- }) => {
- const visuals = getModeVisuals(provider, option.id, providerDefinitions);
- const IconComponent = visuals?.icon ? MODE_ICONS[visuals.icon] : ShieldCheck;
- return (
- }
- />
- );
- },
+ }) => (
+
+ ),
[provider, providerDefinitions, theme.colors.foreground],
);
@@ -1021,6 +1019,40 @@ function ThinkingMenuItem({
);
}
+function ModeComboboxOption({
+ option,
+ selected,
+ active,
+ onPress,
+ provider,
+ providerDefinitions,
+ iconColor,
+}: {
+ option: ComboboxOption;
+ selected: boolean;
+ active: boolean;
+ onPress: () => void;
+ provider: string;
+ providerDefinitions: AgentProviderDefinition[];
+ iconColor: string;
+}) {
+ const visuals = getModeVisuals(provider, option.id, providerDefinitions);
+ const IconComponent = visuals?.icon ? MODE_ICONS[visuals.icon] : ShieldCheck;
+ const leadingSlot = useMemo(
+ () => ,
+ [IconComponent, iconColor],
+ );
+ return (
+
+ );
+}
+
function ModeMenuItem({
mode,
provider,
@@ -1042,12 +1074,13 @@ function ModeMenuItem({
onSelectMode?.(mode.id);
}, [mode.id, onSelectMode]);
+ const leadingIcon = useMemo(
+ () => ,
+ [Icon, theme.colors.foreground],
+ );
+
return (
- }
- >
+
{mode.label}
);
diff --git a/packages/app/src/components/file-explorer-pane.tsx b/packages/app/src/components/file-explorer-pane.tsx
index 82c978612..e3f86ee6e 100644
--- a/packages/app/src/components/file-explorer-pane.tsx
+++ b/packages/app/src/components/file-explorer-pane.tsx
@@ -142,6 +142,15 @@ function TreeRowItem({
[isExpanded],
);
+ const copyLeading = useMemo(
+ () => ,
+ [theme.colors.foregroundMuted],
+ );
+ const downloadLeading = useMemo(
+ () => ,
+ [theme.colors.foregroundMuted],
+ );
+
return (
{depth > 0 && Array.from({ length: depth }, (_, i) => )}
@@ -187,17 +196,11 @@ function TreeRowItem({
- }
- onSelect={handleCopy}
- >
+
Copy path
{entry.kind === "file" ? (
- }
- onSelect={handleDownload}
- >
+
Download
) : null}
diff --git a/packages/app/src/components/git-actions-split-button.tsx b/packages/app/src/components/git-actions-split-button.tsx
index 823194293..5113a3f65 100644
--- a/packages/app/src/components/git-actions-split-button.tsx
+++ b/packages/app/src/components/git-actions-split-button.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useMemo, type ReactElement } from "react";
+import { useCallback, useMemo } from "react";
import {
View,
Text,
@@ -17,6 +17,7 @@ import {
} from "@/components/ui/dropdown-menu";
import { Shortcut } from "@/components/ui/shortcut";
import { useShortcutKeys } from "@/hooks/use-shortcut-keys";
+import type { ShortcutKey } from "@/utils/format-shortcut";
import { useToast } from "@/contexts/toast-context";
import type { GitAction, GitActions } from "@/components/git-actions-policy";
@@ -28,7 +29,7 @@ interface GitActionsSplitButtonProps {
interface GitActionMenuItemProps {
action: GitAction;
onSelect: (action: GitAction) => void;
- trailing?: ReactElement | null;
+ archiveShortcutKeys?: ShortcutKey[][] | null;
needsSeparator?: boolean;
showSeparator?: boolean;
closeOnSelect?: boolean;
@@ -37,12 +38,19 @@ interface GitActionMenuItemProps {
function GitActionMenuItem({
action,
onSelect,
- trailing,
+ archiveShortcutKeys,
needsSeparator,
showSeparator,
closeOnSelect,
}: GitActionMenuItemProps) {
const handleSelect = useCallback(() => onSelect(action), [onSelect, action]);
+ const trailing = useMemo(
+ () =>
+ action.id === "archive-worktree" && archiveShortcutKeys ? (
+
+ ) : undefined,
+ [action.id, archiveShortcutKeys],
+ );
return (
{needsSeparator && showSeparator ? : null}
@@ -154,11 +162,7 @@ export function GitActionsSplitButton({ gitActions, hideLabels }: GitActionsSpli
key={action.id}
action={action}
onSelect={handleActionSelect}
- trailing={
- action.id === "archive-worktree" && archiveShortcutKeys ? (
-
- ) : undefined
- }
+ archiveShortcutKeys={archiveShortcutKeys}
needsSeparator={
action.id === "merge-from-base" || action.id === "archive-worktree"
}
diff --git a/packages/app/src/components/message.tsx b/packages/app/src/components/message.tsx
index bb08ed67f..9a9ccb070 100644
--- a/packages/app/src/components/message.tsx
+++ b/packages/app/src/components/message.tsx
@@ -1129,26 +1129,27 @@ const NativeExpandableBadgeShimmer = memo(function NativeExpandableBadgeShimmer(
[nativeShimmerPeakStyle, peakWidth, rowHeight],
);
+ const maskElement = useMemo(
+ () => (
+
+
+ {label}
+
+ {secondaryLabel ? (
+
+ {secondaryLabel}
+
+ ) : (
+
+ )}
+
+ ),
+ [nativeShimmerMaskStyle, nativeLabelMaskStyle, nativeSecondaryMaskStyle, label, secondaryLabel],
+ );
+
return (
-
-
- {label}
-
- {secondaryLabel ? (
-
- {secondaryLabel}
-
- ) : (
-
- )}
-
- }
- >
+