Add Changes overflow menu and primary action toolbar
This commit is contained in:
@@ -29,6 +29,12 @@ function getChangesActionButton(page: Page, label: string) {
|
|||||||
return getChangesActionLabel(page, label).locator('..');
|
return getChangesActionLabel(page, label).locator('..');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openChangesOverflowMenu(page: Page) {
|
||||||
|
const menuButton = page.getByTestId('changes-overflow-menu').first();
|
||||||
|
await expect(menuButton).toBeVisible();
|
||||||
|
await menuButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
async function openChangesPanel(page: Page, options?: { expectGit?: boolean }) {
|
async function openChangesPanel(page: Page, options?: { expectGit?: boolean }) {
|
||||||
const changesHeader = getChangesHeader(page);
|
const changesHeader = getChangesHeader(page);
|
||||||
if (!(await changesHeader.isVisible())) {
|
if (!(await changesHeader.isVisible())) {
|
||||||
@@ -306,7 +312,9 @@ test('checkout-first Changes panel ship loop', async ({ page }) => {
|
|||||||
await refreshChangesTab(page);
|
await refreshChangesTab(page);
|
||||||
await expect(getChangesActionLabel(page, 'Merge to base')).toHaveCount(0, { timeout: 30000 });
|
await expect(getChangesActionLabel(page, 'Merge to base')).toHaveCount(0, { timeout: 30000 });
|
||||||
|
|
||||||
await getChangesActionButton(page, 'Archive').click();
|
await openChangesOverflowMenu(page);
|
||||||
|
await expect(page.getByTestId('changes-menu-archive')).toBeVisible();
|
||||||
|
await page.getByTestId('changes-menu-archive').click();
|
||||||
// Archiving a worktree deletes agents and redirects to home
|
// Archiving a worktree deletes agents and redirects to home
|
||||||
await expect(page).toHaveURL(/\/$/, { timeout: 30000 });
|
await expect(page).toHaveURL(/\/$/, { timeout: 30000 });
|
||||||
await setWorkingDirectory(page, repo.path);
|
await setWorkingDirectory(page, repo.path);
|
||||||
@@ -331,9 +339,7 @@ test('checkout-first Changes panel ship loop', async ({ page }) => {
|
|||||||
await waitForAssistantText(page, 'NON-GIT');
|
await waitForAssistantText(page, 'NON-GIT');
|
||||||
await openChangesPanel(page, { expectGit: false });
|
await openChangesPanel(page, { expectGit: false });
|
||||||
await expect(getChangesScope(page).getByTestId('changes-not-git')).toBeVisible();
|
await expect(getChangesScope(page).getByTestId('changes-not-git')).toBeVisible();
|
||||||
await expect(getChangesActionButton(page, 'Commit')).toHaveAttribute('aria-disabled', 'true');
|
await expect(getChangesScope(page).getByTestId('changes-toolbar')).toHaveCount(0);
|
||||||
await expect(getChangesActionButton(page, 'Create PR')).toHaveAttribute('aria-disabled', 'true');
|
|
||||||
await expect(getChangesActionLabel(page, 'Merge to base')).toHaveCount(0);
|
|
||||||
} finally {
|
} finally {
|
||||||
await rm(nonGitDir, { recursive: true, force: true });
|
await rm(nonGitDir, { recursive: true, force: true });
|
||||||
await repo.cleanup();
|
await repo.cleanup();
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import {
|
|||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Pressable,
|
Pressable,
|
||||||
FlatList,
|
FlatList,
|
||||||
|
Modal,
|
||||||
|
useWindowDimensions,
|
||||||
|
type LayoutChangeEvent,
|
||||||
type NativeSyntheticEvent,
|
type NativeSyntheticEvent,
|
||||||
type NativeScrollEvent,
|
type NativeScrollEvent,
|
||||||
type ListRenderItem,
|
type ListRenderItem,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gesture-handler";
|
import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gesture-handler";
|
||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { ChevronRight, GitBranch } from "lucide-react-native";
|
import { ChevronRight, GitBranch, MoreVertical, RotateCcw } from "lucide-react-native";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import {
|
import {
|
||||||
@@ -348,12 +351,16 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
|
|||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const { width: windowWidth, height: windowHeight } = useWindowDimensions();
|
||||||
const client = useSessionStore(
|
const client = useSessionStore(
|
||||||
(state) => state.sessions[serverId]?.client ?? null
|
(state) => state.sessions[serverId]?.client ?? null
|
||||||
);
|
);
|
||||||
const [diffMode, setDiffMode] = useState<"uncommitted" | "base">("uncommitted");
|
const [diffMode, setDiffMode] = useState<"uncommitted" | "base">("uncommitted");
|
||||||
const [actionError, setActionError] = useState<string | null>(null);
|
const [actionError, setActionError] = useState<string | null>(null);
|
||||||
const [actionStatus, setActionStatus] = useState<string | null>(null);
|
const [actionStatus, setActionStatus] = useState<string | null>(null);
|
||||||
|
const [overflowVisible, setOverflowVisible] = useState(false);
|
||||||
|
const [overflowAnchor, setOverflowAnchor] = useState({ left: 0, top: 0 });
|
||||||
|
const [overflowHeight, setOverflowHeight] = useState(0);
|
||||||
const { status, isLoading: isStatusLoading, isFetching: isStatusFetching, isError: isStatusError, error: statusError, refresh: refreshStatus } =
|
const { status, isLoading: isStatusLoading, isFetching: isStatusFetching, isError: isStatusError, error: statusError, refresh: refreshStatus } =
|
||||||
useCheckoutStatusQuery({ serverId, agentId });
|
useCheckoutStatusQuery({ serverId, agentId });
|
||||||
const gitStatus = status && status.isGit ? status : null;
|
const gitStatus = status && status.isGit ? status : null;
|
||||||
@@ -421,6 +428,25 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
|
|||||||
void refreshPrStatus();
|
void refreshPrStatus();
|
||||||
}, [refreshDiff, refreshStatus, refreshPrStatus]);
|
}, [refreshDiff, refreshStatus, refreshPrStatus]);
|
||||||
|
|
||||||
|
const handleOpenOverflowMenu = useCallback((event: any) => {
|
||||||
|
const { pageX, pageY } = event?.nativeEvent ?? {};
|
||||||
|
setOverflowAnchor({
|
||||||
|
left: typeof pageX === "number" ? pageX : 0,
|
||||||
|
top: typeof pageY === "number" ? pageY : 0,
|
||||||
|
});
|
||||||
|
setOverflowVisible(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleCloseOverflowMenu = useCallback(() => {
|
||||||
|
setOverflowVisible(false);
|
||||||
|
setOverflowHeight(0);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOverflowLayout = useCallback((event: LayoutChangeEvent) => {
|
||||||
|
const { height } = event.nativeEvent.layout;
|
||||||
|
setOverflowHeight((current) => (current === height ? current : height));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleToggleExpanded = useCallback((path: string) => {
|
const handleToggleExpanded = useCallback((path: string) => {
|
||||||
setExpandedByPath((prev) => ({
|
setExpandedByPath((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@@ -672,6 +698,88 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PrimaryAction = {
|
||||||
|
key: "commit" | "create_pr" | "merge";
|
||||||
|
label: string;
|
||||||
|
testID: string;
|
||||||
|
disabled: boolean;
|
||||||
|
isPending: boolean;
|
||||||
|
onPress: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const primaryAction: PrimaryAction | null = useMemo(() => {
|
||||||
|
if (!isGit) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (showCommitAction) {
|
||||||
|
return {
|
||||||
|
key: "commit",
|
||||||
|
label: "Commit",
|
||||||
|
testID: "changes-primary-commit",
|
||||||
|
disabled: commitDisabled,
|
||||||
|
isPending: commitMutation.isPending,
|
||||||
|
onPress: () => commitMutation.mutate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (showCreatePrAction) {
|
||||||
|
return {
|
||||||
|
key: "create_pr",
|
||||||
|
label: "Create PR",
|
||||||
|
testID: "changes-primary-create-pr",
|
||||||
|
disabled: prDisabled,
|
||||||
|
isPending: prMutation.isPending,
|
||||||
|
onPress: () => prMutation.mutate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (showMergeAction) {
|
||||||
|
return {
|
||||||
|
key: "merge",
|
||||||
|
label: "Merge to base",
|
||||||
|
testID: "changes-primary-merge",
|
||||||
|
disabled: mergeDisabled,
|
||||||
|
isPending: mergeMutation.isPending,
|
||||||
|
onPress: () => mergeMutation.mutate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [
|
||||||
|
commitDisabled,
|
||||||
|
commitMutation,
|
||||||
|
isGit,
|
||||||
|
mergeDisabled,
|
||||||
|
mergeMutation,
|
||||||
|
prDisabled,
|
||||||
|
prMutation,
|
||||||
|
showCommitAction,
|
||||||
|
showCreatePrAction,
|
||||||
|
showMergeAction,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const overflowPosition = useMemo(() => {
|
||||||
|
if (!overflowVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const menuWidth = 220;
|
||||||
|
const horizontalPadding = theme.spacing[2];
|
||||||
|
const verticalPadding = theme.spacing[2];
|
||||||
|
const maxLeft = Math.max(horizontalPadding, windowWidth - menuWidth - horizontalPadding);
|
||||||
|
const maxTop = Math.max(verticalPadding, windowHeight - overflowHeight - verticalPadding);
|
||||||
|
const left = Math.min(
|
||||||
|
Math.max(overflowAnchor.left - menuWidth + horizontalPadding, horizontalPadding),
|
||||||
|
maxLeft
|
||||||
|
);
|
||||||
|
const top = Math.min(Math.max(overflowAnchor.top + verticalPadding, verticalPadding), maxTop);
|
||||||
|
return { top, left, width: menuWidth };
|
||||||
|
}, [
|
||||||
|
overflowAnchor.left,
|
||||||
|
overflowAnchor.top,
|
||||||
|
overflowHeight,
|
||||||
|
overflowVisible,
|
||||||
|
theme.spacing,
|
||||||
|
windowHeight,
|
||||||
|
windowWidth,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.header} testID="changes-header">
|
<View style={styles.header} testID="changes-header">
|
||||||
@@ -722,67 +830,43 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.actionsRow}>
|
{isGit ? (
|
||||||
{showCommitAction ? (
|
<View style={styles.toolbarRow} testID="changes-toolbar">
|
||||||
<Pressable
|
<View style={styles.toolbarPrimary}>
|
||||||
testID="changes-action-commit"
|
{primaryAction ? (
|
||||||
style={[styles.actionButton, commitDisabled && styles.actionButtonDisabled]}
|
<Pressable
|
||||||
onPress={() => commitMutation.mutate()}
|
testID={primaryAction.testID}
|
||||||
disabled={commitDisabled}
|
style={[
|
||||||
>
|
styles.primaryActionButton,
|
||||||
{commitMutation.isPending ? (
|
primaryAction.disabled && styles.primaryActionButtonDisabled,
|
||||||
<ActivityIndicator size="small" color={theme.colors.foreground} />
|
]}
|
||||||
|
onPress={primaryAction.onPress}
|
||||||
|
disabled={primaryAction.disabled}
|
||||||
|
>
|
||||||
|
{primaryAction.isPending ? (
|
||||||
|
<ActivityIndicator size="small" color={theme.colors.foreground} />
|
||||||
|
) : (
|
||||||
|
<Text style={styles.primaryActionText}>{primaryAction.label}</Text>
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
) : (
|
) : (
|
||||||
<Text style={styles.actionButtonText}>Commit</Text>
|
<View style={styles.toolbarPrimarySpacer} />
|
||||||
)}
|
)}
|
||||||
</Pressable>
|
</View>
|
||||||
) : null}
|
<View style={styles.toolbarRight}>
|
||||||
{showCreatePrAction ? (
|
<Pressable
|
||||||
<Pressable
|
testID="changes-overflow-menu"
|
||||||
testID="changes-action-create-pr"
|
onPress={handleOpenOverflowMenu}
|
||||||
style={[styles.actionButton, prDisabled && styles.actionButtonDisabled]}
|
hitSlop={8}
|
||||||
onPress={() => prMutation.mutate()}
|
style={styles.iconButton}
|
||||||
disabled={prDisabled}
|
accessibilityRole="button"
|
||||||
>
|
accessibilityLabel="More actions"
|
||||||
{prMutation.isPending ? (
|
>
|
||||||
<ActivityIndicator size="small" color={theme.colors.foreground} />
|
<MoreVertical size={16} color={theme.colors.foregroundMuted} />
|
||||||
) : (
|
</Pressable>
|
||||||
<Text style={styles.actionButtonText}>Create PR</Text>
|
</View>
|
||||||
)}
|
</View>
|
||||||
</Pressable>
|
) : null}
|
||||||
) : null}
|
|
||||||
{showMergeAction ? (
|
|
||||||
<Pressable
|
|
||||||
testID="changes-action-merge"
|
|
||||||
style={[styles.actionButton, mergeDisabled && styles.actionButtonDisabled]}
|
|
||||||
onPress={() => mergeMutation.mutate()}
|
|
||||||
disabled={mergeDisabled}
|
|
||||||
>
|
|
||||||
{mergeMutation.isPending ? (
|
|
||||||
<ActivityIndicator size="small" color={theme.colors.foreground} />
|
|
||||||
) : (
|
|
||||||
<Text style={styles.actionButtonText}>Merge to base</Text>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
) : null}
|
|
||||||
<Pressable
|
|
||||||
testID="changes-action-archive"
|
|
||||||
style={[styles.actionButton, archiveDisabled && styles.actionButtonDisabled]}
|
|
||||||
onPress={() => archiveMutation.mutate()}
|
|
||||||
disabled={archiveDisabled}
|
|
||||||
>
|
|
||||||
{archiveMutation.isPending ? (
|
|
||||||
<ActivityIndicator size="small" color={theme.colors.foreground} />
|
|
||||||
) : (
|
|
||||||
<Text style={styles.actionButtonText}>Archive</Text>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={styles.debugText} testID="changes-debug-state">
|
|
||||||
mode={diffMode} files={files.length} isGit={String(isGit)} ahead=
|
|
||||||
{gitStatus?.aheadBehind ? String(gitStatus.aheadBehind.ahead) : "null"}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{actionStatus ? <Text style={styles.actionStatusText}>{actionStatus}</Text> : null}
|
{actionStatus ? <Text style={styles.actionStatusText}>{actionStatus}</Text> : null}
|
||||||
{actionError ? <Text style={styles.actionErrorText}>{actionError}</Text> : null}
|
{actionError ? <Text style={styles.actionErrorText}>{actionError}</Text> : null}
|
||||||
@@ -799,6 +883,121 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<View style={styles.diffContainer}>{bodyContent}</View>
|
<View style={styles.diffContainer}>{bodyContent}</View>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
visible={overflowVisible}
|
||||||
|
animationType="fade"
|
||||||
|
transparent={true}
|
||||||
|
onRequestClose={handleCloseOverflowMenu}
|
||||||
|
>
|
||||||
|
<View style={styles.menuOverlay}>
|
||||||
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel="Overflow menu backdrop"
|
||||||
|
style={styles.menuBackdrop}
|
||||||
|
onPress={handleCloseOverflowMenu}
|
||||||
|
/>
|
||||||
|
{overflowPosition ? (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.dropdownMenu,
|
||||||
|
{
|
||||||
|
position: "absolute",
|
||||||
|
top: overflowPosition.top,
|
||||||
|
left: overflowPosition.left,
|
||||||
|
width: overflowPosition.width,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onLayout={handleOverflowLayout}
|
||||||
|
>
|
||||||
|
<Pressable
|
||||||
|
testID="changes-menu-refresh"
|
||||||
|
style={styles.menuItem}
|
||||||
|
onPress={() => {
|
||||||
|
handleCloseOverflowMenu();
|
||||||
|
handleRefresh();
|
||||||
|
}}
|
||||||
|
accessibilityRole="button"
|
||||||
|
>
|
||||||
|
<RotateCcw size={16} color={theme.colors.foreground} />
|
||||||
|
<Text style={styles.menuItemText}>Refresh</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<View style={styles.menuDivider} />
|
||||||
|
|
||||||
|
{showCommitAction && primaryAction?.key !== "commit" ? (
|
||||||
|
<Pressable
|
||||||
|
testID="changes-menu-commit"
|
||||||
|
style={[styles.menuItem, commitDisabled && styles.menuItemDisabled]}
|
||||||
|
onPress={() => {
|
||||||
|
if (commitDisabled) return;
|
||||||
|
handleCloseOverflowMenu();
|
||||||
|
commitMutation.mutate();
|
||||||
|
}}
|
||||||
|
disabled={commitDisabled}
|
||||||
|
accessibilityRole="button"
|
||||||
|
>
|
||||||
|
<Text style={styles.menuItemText}>Commit</Text>
|
||||||
|
</Pressable>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{showCreatePrAction && primaryAction?.key !== "create_pr" ? (
|
||||||
|
<Pressable
|
||||||
|
testID="changes-menu-create-pr"
|
||||||
|
style={[styles.menuItem, prDisabled && styles.menuItemDisabled]}
|
||||||
|
onPress={() => {
|
||||||
|
if (prDisabled) return;
|
||||||
|
handleCloseOverflowMenu();
|
||||||
|
prMutation.mutate();
|
||||||
|
}}
|
||||||
|
disabled={prDisabled}
|
||||||
|
accessibilityRole="button"
|
||||||
|
>
|
||||||
|
<Text style={styles.menuItemText}>Create PR</Text>
|
||||||
|
</Pressable>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{showMergeAction && primaryAction?.key !== "merge" ? (
|
||||||
|
<Pressable
|
||||||
|
testID="changes-menu-merge"
|
||||||
|
style={[styles.menuItem, mergeDisabled && styles.menuItemDisabled]}
|
||||||
|
onPress={() => {
|
||||||
|
if (mergeDisabled) return;
|
||||||
|
handleCloseOverflowMenu();
|
||||||
|
mergeMutation.mutate();
|
||||||
|
}}
|
||||||
|
disabled={mergeDisabled}
|
||||||
|
accessibilityRole="button"
|
||||||
|
>
|
||||||
|
<Text style={styles.menuItemText}>Merge to base</Text>
|
||||||
|
</Pressable>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<View style={styles.menuDivider} />
|
||||||
|
|
||||||
|
<Pressable
|
||||||
|
testID="changes-menu-archive"
|
||||||
|
style={[
|
||||||
|
styles.menuItem,
|
||||||
|
styles.menuItemDestructive,
|
||||||
|
archiveDisabled && styles.menuItemDisabled,
|
||||||
|
]}
|
||||||
|
onPress={() => {
|
||||||
|
if (archiveDisabled) return;
|
||||||
|
handleCloseOverflowMenu();
|
||||||
|
archiveMutation.mutate();
|
||||||
|
}}
|
||||||
|
disabled={archiveDisabled}
|
||||||
|
accessibilityRole="button"
|
||||||
|
>
|
||||||
|
<Text style={[styles.menuItemText, styles.menuItemTextDestructive]}>
|
||||||
|
Archive worktree
|
||||||
|
</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -855,35 +1054,97 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
modeToggleTextActive: {
|
modeToggleTextActive: {
|
||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
},
|
},
|
||||||
actionsRow: {
|
toolbarRow: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
flexWrap: "wrap",
|
alignItems: "center",
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
paddingHorizontal: theme.spacing[3],
|
paddingHorizontal: theme.spacing[3],
|
||||||
paddingTop: theme.spacing[2],
|
paddingTop: theme.spacing[2],
|
||||||
paddingBottom: theme.spacing[1],
|
paddingBottom: theme.spacing[1],
|
||||||
},
|
},
|
||||||
actionButton: {
|
toolbarPrimary: {
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
},
|
||||||
|
toolbarPrimarySpacer: {
|
||||||
|
height: 32,
|
||||||
|
},
|
||||||
|
toolbarRight: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: theme.spacing[1],
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
primaryActionButton: {
|
||||||
paddingHorizontal: theme.spacing[3],
|
paddingHorizontal: theme.spacing[3],
|
||||||
paddingVertical: theme.spacing[2],
|
paddingVertical: theme.spacing[2],
|
||||||
borderRadius: theme.borderRadius.md,
|
borderRadius: theme.borderRadius.md,
|
||||||
backgroundColor: theme.colors.surface2,
|
backgroundColor: theme.colors.surface2,
|
||||||
borderWidth: theme.borderWidth[1],
|
borderWidth: theme.borderWidth[1],
|
||||||
borderColor: theme.colors.borderAccent,
|
borderColor: theme.colors.borderAccent,
|
||||||
|
alignSelf: "flex-start",
|
||||||
},
|
},
|
||||||
actionButtonDisabled: {
|
primaryActionButtonDisabled: {
|
||||||
opacity: 0.5,
|
opacity: 0.5,
|
||||||
},
|
},
|
||||||
actionButtonText: {
|
primaryActionText: {
|
||||||
fontSize: theme.fontSize.xs,
|
fontSize: theme.fontSize.xs,
|
||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
fontWeight: theme.fontWeight.medium,
|
fontWeight: theme.fontWeight.medium,
|
||||||
},
|
},
|
||||||
debugText: {
|
iconButton: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
borderRadius: theme.borderRadius.md,
|
||||||
|
},
|
||||||
|
menuOverlay: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
menuBackdrop: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
dropdownMenu: {
|
||||||
|
backgroundColor: theme.colors.surface0,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: theme.colors.borderAccent,
|
||||||
|
borderRadius: theme.borderRadius.lg,
|
||||||
|
overflow: "hidden",
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOffset: { width: 0, height: 4 },
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 8,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: theme.spacing[2],
|
||||||
paddingHorizontal: theme.spacing[3],
|
paddingHorizontal: theme.spacing[3],
|
||||||
paddingBottom: theme.spacing[1],
|
paddingVertical: theme.spacing[2],
|
||||||
fontSize: theme.fontSize.xs,
|
},
|
||||||
color: theme.colors.foregroundMuted,
|
menuItemDisabled: {
|
||||||
|
opacity: 0.5,
|
||||||
|
},
|
||||||
|
menuItemText: {
|
||||||
|
fontSize: theme.fontSize.sm,
|
||||||
|
color: theme.colors.foreground,
|
||||||
|
fontWeight: theme.fontWeight.medium,
|
||||||
|
},
|
||||||
|
menuItemDestructive: {
|
||||||
|
backgroundColor: "rgba(248, 81, 73, 0.08)",
|
||||||
|
},
|
||||||
|
menuItemTextDestructive: {
|
||||||
|
color: theme.colors.destructive,
|
||||||
|
},
|
||||||
|
menuDivider: {
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: theme.colors.border,
|
||||||
},
|
},
|
||||||
actionStatusText: {
|
actionStatusText: {
|
||||||
paddingHorizontal: theme.spacing[3],
|
paddingHorizontal: theme.spacing[3],
|
||||||
|
|||||||
Reference in New Issue
Block a user