fix(app): polish workspace navigation surfaces
Use mobile action sheets and long-press file menus while preserving provider context across sheet portals. Keep sidebar and file-pane glyphs on shared visual rails, avoid scrollbar layout shifts, and hide keyboard affordances where shortcuts are unavailable.
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
type ViewStyle,
|
||||
} from "react-native";
|
||||
import { StyleSheet, useUnistyles, withUnistyles } from "react-native-unistyles";
|
||||
import { WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
|
||||
import { useIsCompactFormFactor, WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import { ChevronDown, Eye, EyeOff, RotateCw } from "lucide-react-native";
|
||||
import { MaterialFileIcon } from "@/components/material-file-icon";
|
||||
@@ -20,9 +20,14 @@ import {
|
||||
TreeChevron,
|
||||
TreeIndentGuides,
|
||||
treeRowPaddingLeft,
|
||||
WORKSPACE_FILE_ROW_TRAILING_PADDING,
|
||||
WORKSPACE_FILE_ROW_VERTICAL_PADDING,
|
||||
} from "@/components/tree-primitives";
|
||||
import { LoadingSpinner } from "@/components/ui/loading-spinner";
|
||||
import {
|
||||
useOverlayFlatListScrollbar,
|
||||
type OverlayFlatListScrollbar,
|
||||
} from "@/components/ui/overlay-scrollbar/use-overlay-flat-list-scrollbar";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
import type {
|
||||
AgentFileExplorerState,
|
||||
@@ -174,12 +179,7 @@ function TreeRowItem({
|
||||
|
||||
return (
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger
|
||||
enabledOnMobile={false}
|
||||
onPress={handlePress}
|
||||
style={pressableStyle}
|
||||
testID={testID}
|
||||
>
|
||||
<ContextMenuTrigger onPress={handlePress} style={pressableStyle} testID={testID}>
|
||||
<TreeIndentGuides depth={depth} />
|
||||
<View ref={dragSourceRef} style={styles.entryInfo}>
|
||||
<View style={styles.entryIcon}>
|
||||
@@ -226,6 +226,7 @@ export function FileExplorerPane({
|
||||
onAddToChat,
|
||||
}: FileExplorerPaneProps) {
|
||||
const { t } = useTranslation();
|
||||
const isCompact = useIsCompactFormFactor();
|
||||
|
||||
const normalizedWorkspaceRoot = useMemo(() => workspaceRoot.trim(), [workspaceRoot]);
|
||||
const workspaceStateKey = useMemo(
|
||||
@@ -278,6 +279,7 @@ export function FileExplorerPane({
|
||||
);
|
||||
|
||||
const treeListRef = useRef<FlatList<ExplorerTreeRow>>(null);
|
||||
const scrollbar = useOverlayFlatListScrollbar(treeListRef, { enabled: !isCompact });
|
||||
|
||||
const hasInitializedRef = useRef(false);
|
||||
|
||||
@@ -518,6 +520,7 @@ export function FileExplorerPane({
|
||||
currentSortLabel={currentSortLabel}
|
||||
isRefreshFetching={isRefreshFetching}
|
||||
treeListRef={treeListRef}
|
||||
scrollbar={scrollbar}
|
||||
renderTreeRow={renderTreeRow}
|
||||
handleSortCycle={handleSortCycle}
|
||||
handleToggleHiddenFiles={handleToggleHiddenFiles}
|
||||
@@ -539,6 +542,7 @@ interface FileExplorerPaneContentProps {
|
||||
currentSortLabel: string;
|
||||
isRefreshFetching: boolean;
|
||||
treeListRef: RefObject<FlatList<ExplorerTreeRow> | null>;
|
||||
scrollbar: OverlayFlatListScrollbar;
|
||||
renderTreeRow: (info: ListRenderItemInfo<ExplorerTreeRow>) => ReactElement;
|
||||
handleSortCycle: () => void;
|
||||
handleToggleHiddenFiles: () => void;
|
||||
@@ -560,6 +564,7 @@ function FileExplorerPaneContent(props: FileExplorerPaneContentProps) {
|
||||
currentSortLabel,
|
||||
isRefreshFetching,
|
||||
treeListRef,
|
||||
scrollbar,
|
||||
renderTreeRow,
|
||||
handleSortCycle,
|
||||
handleToggleHiddenFiles,
|
||||
@@ -682,12 +687,17 @@ function FileExplorerPaneContent(props: FileExplorerPaneContentProps) {
|
||||
keyExtractor={treeRowKeyExtractor}
|
||||
testID="file-explorer-tree-scroll"
|
||||
contentContainerStyle={styles.entriesContent}
|
||||
showsVerticalScrollIndicator
|
||||
onLayout={scrollbar.onLayout}
|
||||
onScroll={scrollbar.onScroll}
|
||||
onContentSizeChange={scrollbar.onContentSizeChange}
|
||||
scrollEventThrottle={16}
|
||||
showsVerticalScrollIndicator={!scrollbar.enabled}
|
||||
initialNumToRender={24}
|
||||
maxToRenderPerBatch={40}
|
||||
windowSize={12}
|
||||
/>
|
||||
)}
|
||||
{treeRows.length > 0 ? scrollbar.overlay : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1055,7 +1065,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: WORKSPACE_FILE_ROW_VERTICAL_PADDING,
|
||||
paddingRight: theme.spacing[3],
|
||||
paddingRight: WORKSPACE_FILE_ROW_TRAILING_PADDING,
|
||||
},
|
||||
entryRowActive: {
|
||||
backgroundColor: theme.colors.surfaceSidebarHover,
|
||||
|
||||
Reference in New Issue
Block a user