mirror of https://github.com/kortix-ai/suna.git
feat: fix and add bottom drawer
This commit is contained in:
parent
bdce7bd72c
commit
1f156664f8
|
@ -4,12 +4,13 @@ import { usePanelTopOffset } from '@/constants/SafeArea';
|
|||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useThemedStyles } from '@/hooks/useThemeColor';
|
||||
import { useIsNewChatMode, useResetNewChatSession, useSelectedProject, useSetNewChatMode, useSetSelectedProject } from '@/stores/ui-store';
|
||||
import { SquarePen } from 'lucide-react-native';
|
||||
import { ChevronsUpDown, SquarePen } from 'lucide-react-native';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { ScrollView, TouchableOpacity, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { ChatActionModal } from './ChatActionModal';
|
||||
import { DeleteConfirmationModal } from './DeleteConfirmationModal';
|
||||
import { SettingsDrawer } from './SettingsDrawer';
|
||||
import { ShareModal } from './ShareModal';
|
||||
import { SkeletonProjects } from './Skeleton';
|
||||
import { Body, Caption, H3 } from './Typography';
|
||||
|
@ -27,6 +28,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
const [deleteModalVisible, setDeleteModalVisible] = useState(false);
|
||||
const [shareModalVisible, setShareModalVisible] = useState(false);
|
||||
const [actionModalVisible, setActionModalVisible] = useState(false);
|
||||
const [settingsDrawerVisible, setSettingsDrawerVisible] = useState(false);
|
||||
const [projectToDelete, setProjectToDelete] = useState<{ id: string; name: string } | null>(null);
|
||||
const [projectToShare, setProjectToShare] = useState<{ id: string; name: string; isPublic?: boolean } | null>(null);
|
||||
const [selectedChatLayout, setSelectedChatLayout] = useState<{ x: number; y: number; width: number; height: number } | undefined>();
|
||||
|
@ -39,7 +41,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
const deleteProjectMutation = useDeleteProject();
|
||||
|
||||
// Use auth context
|
||||
const { user, signOut } = useAuth();
|
||||
const { user } = useAuth();
|
||||
|
||||
// Use zustand for chat state
|
||||
const selectedProject = useSelectedProject();
|
||||
|
@ -214,19 +216,6 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
paddingVertical: 12,
|
||||
fontStyle: 'italic' as const,
|
||||
},
|
||||
signOutButton: {
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 12,
|
||||
borderRadius: 6,
|
||||
backgroundColor: theme.mutedWithOpacity(0.1),
|
||||
marginTop: 8,
|
||||
},
|
||||
signOutText: {
|
||||
color: theme.destructive,
|
||||
fontSize: 13,
|
||||
fontFamily: fontWeights[500],
|
||||
textAlign: 'center' as const,
|
||||
},
|
||||
selectedTaskItem: {
|
||||
backgroundColor: theme.mutedWithOpacity(0.1),
|
||||
borderRadius: 12,
|
||||
|
@ -234,6 +223,9 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
selectedTaskText: {
|
||||
color: theme.foreground,
|
||||
},
|
||||
settingsIcon: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
}));
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
@ -301,15 +293,6 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
));
|
||||
};
|
||||
|
||||
const handleSignOut = async () => {
|
||||
try {
|
||||
await signOut();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Error signing out:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleProjectSelect = (project: any) => {
|
||||
console.log('[LeftPanel] Project selected:', project.name, 'isNewChat:', project.isNewChat);
|
||||
|
||||
|
@ -412,6 +395,14 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
return name.charAt(0).toUpperCase();
|
||||
};
|
||||
|
||||
const handleSettingsDrawerOpen = () => {
|
||||
setSettingsDrawerVisible(true);
|
||||
};
|
||||
|
||||
const handleSettingsDrawerClose = () => {
|
||||
setSettingsDrawerVisible(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.panel}>
|
||||
<View style={styles.header}>
|
||||
|
@ -466,7 +457,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
|
||||
{/* User Section */}
|
||||
<View style={styles.userSection}>
|
||||
<TouchableOpacity style={styles.userInfo}>
|
||||
<TouchableOpacity style={styles.userInfo} onPress={handleSettingsDrawerOpen}>
|
||||
<View style={styles.userAvatar}>
|
||||
<Caption style={styles.userInitial}>{getUserInitial()}</Caption>
|
||||
</View>
|
||||
|
@ -474,10 +465,7 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
<Body style={styles.userName}>{getUserDisplayName()}</Body>
|
||||
<Caption style={styles.userEmail}>{user?.email || 'No email'}</Caption>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.signOutButton} onPress={handleSignOut}>
|
||||
<Caption style={styles.signOutText}>Sign Out</Caption>
|
||||
<ChevronsUpDown size={16} color={styles.title.color} style={styles.settingsIcon} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
|
@ -508,6 +496,12 @@ export const LeftPanel: React.FC<LeftPanelProps> = ({ isVisible, onClose }) => {
|
|||
onClose={handleDeleteCancel}
|
||||
onConfirm={handleDeleteConfirm}
|
||||
/>
|
||||
|
||||
{/* Settings Drawer */}
|
||||
<SettingsDrawer
|
||||
visible={settingsDrawerVisible}
|
||||
onClose={handleSettingsDrawerClose}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
|
@ -2,6 +2,7 @@ import { Message } from '@/api/chat-api';
|
|||
import { commonStyles } from '@/constants/CommonStyles';
|
||||
import { fontWeights } from '@/constants/Fonts';
|
||||
import { useTheme } from '@/hooks/useThemeColor';
|
||||
import { useOpenToolView } from '@/stores/ui-store';
|
||||
|
||||
import { parseFileAttachments } from '@/utils/file-parser';
|
||||
import { Markdown } from '@/utils/markdown-renderer';
|
||||
|
@ -172,6 +173,7 @@ export const MessageThread: React.FC<MessageThreadProps> = ({
|
|||
sandboxId,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const openToolView = useOpenToolView();
|
||||
|
||||
// Log sandboxId for debugging
|
||||
console.log(`[MessageThread] sandboxId: ${sandboxId || 'undefined'}`);
|
||||
|
@ -248,8 +250,8 @@ export const MessageThread: React.FC<MessageThreadProps> = ({
|
|||
}, []);
|
||||
|
||||
const handleToolPress = useCallback((toolCall: any, messageId: string) => {
|
||||
console.log('Tool pressed:', toolCall, messageId);
|
||||
}, []);
|
||||
openToolView(toolCall, messageId);
|
||||
}, [openToolView]);
|
||||
|
||||
const renderMessage = ({ item }: { item: Message }) => {
|
||||
// Skip rendering pure tool result messages
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
import { fontWeights } from '@/constants/Fonts';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useThemedStyles } from '@/hooks/useThemeColor';
|
||||
import { X } from 'lucide-react-native';
|
||||
import React from 'react';
|
||||
import { Modal, Platform, TouchableOpacity, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Caption, H3 } from './Typography';
|
||||
|
||||
interface SettingsDrawerProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const SettingsDrawer: React.FC<SettingsDrawerProps> = ({ visible, onClose }) => {
|
||||
const insets = useSafeAreaInsets();
|
||||
const { signOut } = useAuth();
|
||||
|
||||
const styles = useThemedStyles((theme) => ({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Platform.OS === 'android' ? 'rgba(0, 0, 0, 0.5)' : 'transparent',
|
||||
justifyContent: 'flex-end' as const,
|
||||
},
|
||||
drawer: {
|
||||
backgroundColor: theme.background,
|
||||
...(Platform.OS === 'ios' ? { height: '100%' as const } : { height: '93%' as const }),
|
||||
borderTopLeftRadius: Platform.OS === 'android' ? 16 : 0,
|
||||
borderTopRightRadius: Platform.OS === 'android' ? 16 : 0,
|
||||
paddingTop: 20,
|
||||
paddingBottom: insets.bottom,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row' as const,
|
||||
justifyContent: 'space-between' as const,
|
||||
alignItems: 'center' as const,
|
||||
paddingHorizontal: 20,
|
||||
paddingBottom: 20,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.border,
|
||||
},
|
||||
title: {
|
||||
color: theme.foreground,
|
||||
},
|
||||
closeButton: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 16,
|
||||
backgroundColor: theme.mutedWithOpacity(0.1),
|
||||
justifyContent: 'center' as const,
|
||||
alignItems: 'center' as const,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 20,
|
||||
},
|
||||
signOutButton: {
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 8,
|
||||
backgroundColor: theme.mutedWithOpacity(0.1),
|
||||
marginTop: 'auto' as const,
|
||||
marginBottom: 20,
|
||||
},
|
||||
signOutText: {
|
||||
color: theme.destructive,
|
||||
fontSize: 15,
|
||||
fontFamily: fontWeights[500],
|
||||
textAlign: 'center' as const,
|
||||
},
|
||||
}));
|
||||
|
||||
const handleSignOut = async () => {
|
||||
try {
|
||||
await signOut();
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Error signing out:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
transparent={Platform.OS === 'android'}
|
||||
animationType="slide"
|
||||
presentationStyle={Platform.OS === 'ios' ? 'pageSheet' : undefined}
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
{Platform.OS === 'android' && (
|
||||
<TouchableOpacity
|
||||
style={{ flex: 1 }}
|
||||
activeOpacity={1}
|
||||
onPress={onClose}
|
||||
/>
|
||||
)}
|
||||
|
||||
<View style={styles.drawer}>
|
||||
<View style={styles.header}>
|
||||
<H3 style={styles.title}>Settings</H3>
|
||||
<TouchableOpacity style={styles.closeButton} onPress={onClose}>
|
||||
<X size={18} color={styles.title.color} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<TouchableOpacity style={styles.signOutButton} onPress={handleSignOut}>
|
||||
<Caption style={styles.signOutText}>Sign Out</Caption>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue