mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Chat Split: land. Controls in Page Menu. Fixes #208
This commit is contained in:
+12
-13
@@ -22,7 +22,6 @@ import { themeBgAppChatComposer } from '~/common/app.theme';
|
||||
import { useFolderStore } from '~/common/state/store-folders';
|
||||
import { useIsMobile } from '~/common/components/useMatchMedia';
|
||||
import { useOptimaLayout, usePluggableOptimaLayout } from '~/common/layout/optima/useOptimaLayout';
|
||||
import { useUXLabsStore } from '~/common/state/store-ux-labs';
|
||||
|
||||
import type { ComposerOutputMultiPart } from './components/composer/composer.types';
|
||||
import { ChatDrawerMemo } from './components/applayout/ChatDrawer';
|
||||
@@ -311,24 +310,23 @@ export function AppChat() {
|
||||
const handleConversationBranch = React.useCallback((conversationId: DConversationId, messageId: string | null): DConversationId | null => {
|
||||
showNextTitle.current = true;
|
||||
const branchedConversationId = branchConversation(conversationId, messageId);
|
||||
if (isSplitPane)
|
||||
openSplitConversationId(branchedConversationId);
|
||||
else
|
||||
setFocusedConversationId(branchedConversationId);
|
||||
addSnackbar({
|
||||
key: 'branch-conversation',
|
||||
message: 'Branch started.',
|
||||
type: 'success',
|
||||
overrides: {
|
||||
autoHideDuration: 3000,
|
||||
autoHideDuration: 2000,
|
||||
startDecorator: <ForkRightIcon />,
|
||||
},
|
||||
});
|
||||
const branchInAltPanel = useUXLabsStore.getState().labsSplitBranching;
|
||||
if (branchInAltPanel)
|
||||
openSplitConversationId(branchedConversationId);
|
||||
else
|
||||
setFocusedConversationId(branchedConversationId);
|
||||
return branchedConversationId;
|
||||
}, [branchConversation, openSplitConversationId, setFocusedConversationId]);
|
||||
}, [branchConversation, isSplitPane, openSplitConversationId, setFocusedConversationId]);
|
||||
|
||||
const handleConversationFlatten = (conversationId: DConversationId) => setFlattenConversationId(conversationId);
|
||||
const handleConversationFlatten = React.useCallback((conversationId: DConversationId) => setFlattenConversationId(conversationId), []);
|
||||
|
||||
const handleConfirmedClearConversation = React.useCallback(() => {
|
||||
if (clearConversationId) {
|
||||
@@ -386,10 +384,8 @@ export function AppChat() {
|
||||
const centerItems = React.useMemo(() =>
|
||||
<ChatDropdowns
|
||||
conversationId={focusedConversationId}
|
||||
isSplitPanes={isSplitPane}
|
||||
onToggleSplitPanes={toggleSplitPane}
|
||||
/>,
|
||||
[focusedConversationId, isSplitPane, toggleSplitPane],
|
||||
[focusedConversationId],
|
||||
);
|
||||
|
||||
const drawerContent = React.useMemo(() =>
|
||||
@@ -410,16 +406,19 @@ export function AppChat() {
|
||||
|
||||
const menuItems = React.useMemo(() =>
|
||||
<ChatMenuItems
|
||||
isMobile={isMobile}
|
||||
conversationId={focusedConversationId}
|
||||
hasConversations={!areChatsEmpty}
|
||||
isConversationEmpty={isFocusedChatEmpty}
|
||||
isMessageSelectionMode={isMessageSelectionMode}
|
||||
isSplitPane={isSplitPane}
|
||||
setIsMessageSelectionMode={setIsMessageSelectionMode}
|
||||
onConversationBranch={handleConversationBranch}
|
||||
onConversationClear={handleConversationClear}
|
||||
onConversationFlatten={handleConversationFlatten}
|
||||
onToggleSplitPanes={toggleSplitPane}
|
||||
/>,
|
||||
[areChatsEmpty, focusedConversationId, handleConversationBranch, handleConversationClear, isFocusedChatEmpty, isMessageSelectionMode],
|
||||
[areChatsEmpty, focusedConversationId, handleConversationBranch, handleConversationClear, handleConversationFlatten, isFocusedChatEmpty, isMessageSelectionMode, isMobile, isSplitPane, toggleSplitPane],
|
||||
);
|
||||
|
||||
usePluggableOptimaLayout(drawerContent, centerItems, menuItems, 'AppChat');
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { IconButton } from '@mui/joy';
|
||||
import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
|
||||
import VerticalSplitOutlinedIcon from '@mui/icons-material/VerticalSplitOutlined';
|
||||
|
||||
import type { DConversationId } from '~/common/state/store-chats';
|
||||
import { GoodTooltip } from '~/common/components/GoodTooltip';
|
||||
import { useUXLabsStore } from '~/common/state/store-ux-labs';
|
||||
|
||||
import { useChatLLMDropdown } from './useLLMDropdown';
|
||||
import { usePersonaIdDropdown } from './usePersonaDropdown';
|
||||
@@ -15,8 +9,6 @@ import { useFolderDropdown } from './folder/useFolderDropdown';
|
||||
|
||||
export function ChatDropdowns(props: {
|
||||
conversationId: DConversationId | null
|
||||
isSplitPanes: boolean
|
||||
onToggleSplitPanes: () => void
|
||||
}) {
|
||||
|
||||
// state
|
||||
@@ -24,9 +16,6 @@ export function ChatDropdowns(props: {
|
||||
const { personaDropdown } = usePersonaIdDropdown(props.conversationId);
|
||||
const { folderDropdown } = useFolderDropdown(props.conversationId);
|
||||
|
||||
// external state
|
||||
const labsSplitBranching = useUXLabsStore(state => state.labsSplitBranching);
|
||||
|
||||
return <>
|
||||
|
||||
{/* Persona selector */}
|
||||
@@ -38,18 +27,5 @@ export function ChatDropdowns(props: {
|
||||
{/* Folder selector */}
|
||||
{folderDropdown}
|
||||
|
||||
{/* Split Panes button */}
|
||||
{labsSplitBranching && (
|
||||
<GoodTooltip title={props.isSplitPanes ? 'Close Split Panes' : 'Split Conversation Vertically'}>
|
||||
<IconButton
|
||||
variant={props.isSplitPanes ? 'outlined' : undefined}
|
||||
onClick={props.onToggleSplitPanes}
|
||||
// sx={{ mx: 'auto' }}
|
||||
>
|
||||
{props.isSplitPanes ? <VerticalSplitIcon /> : <VerticalSplitOutlinedIcon />}
|
||||
</IconButton>
|
||||
</GoodTooltip>
|
||||
)}
|
||||
|
||||
</>;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,14 @@ import CheckBoxOutlinedIcon from '@mui/icons-material/CheckBoxOutlined';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
import CompressIcon from '@mui/icons-material/Compress';
|
||||
import ForkRightIcon from '@mui/icons-material/ForkRight';
|
||||
import HorizontalSplitIcon from '@mui/icons-material/HorizontalSplit';
|
||||
import HorizontalSplitOutlinedIcon from '@mui/icons-material/HorizontalSplitOutlined';
|
||||
import SettingsSuggestIcon from '@mui/icons-material/SettingsSuggest';
|
||||
import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
|
||||
import VerticalSplitOutlinedIcon from '@mui/icons-material/VerticalSplitOutlined';
|
||||
|
||||
import type { DConversationId } from '~/common/state/store-chats';
|
||||
import { GoodTooltip } from '~/common/components/GoodTooltip';
|
||||
import { KeyStroke } from '~/common/components/KeyStroke';
|
||||
import { useOptimaDrawers } from '~/common/layout/optima/useOptimaDrawers';
|
||||
|
||||
@@ -16,14 +21,17 @@ import { useChatShowSystemMessages } from '../../store-app-chat';
|
||||
|
||||
|
||||
export function ChatMenuItems(props: {
|
||||
isMobile: boolean,
|
||||
conversationId: DConversationId | null,
|
||||
hasConversations: boolean,
|
||||
isConversationEmpty: boolean,
|
||||
isMessageSelectionMode: boolean,
|
||||
isSplitPane: boolean
|
||||
setIsMessageSelectionMode: (isMessageSelectionMode: boolean) => void,
|
||||
onConversationBranch: (conversationId: DConversationId, messageId: string | null) => void,
|
||||
onConversationClear: (conversationId: DConversationId) => void,
|
||||
onConversationFlatten: (conversationId: DConversationId) => void,
|
||||
onToggleSplitPanes: () => void,
|
||||
}) {
|
||||
|
||||
// external state
|
||||
@@ -64,6 +72,20 @@ export function ChatMenuItems(props: {
|
||||
|
||||
return <>
|
||||
|
||||
{/* Split/Unsplit panes */}
|
||||
<GoodTooltip title={props.isSplitPane ? 'Close Split Panes' : 'Split Conversation Vertically'}>
|
||||
<MenuItem onClick={props.onToggleSplitPanes}>
|
||||
<ListItemDecorator>{
|
||||
props.isMobile
|
||||
? (props.isSplitPane ? <HorizontalSplitIcon /> : <HorizontalSplitOutlinedIcon />)
|
||||
: (props.isSplitPane ? <VerticalSplitIcon /> : <VerticalSplitOutlinedIcon />)
|
||||
}</ListItemDecorator>
|
||||
{props.isSplitPane ? 'Unsplit' : props.isMobile ? 'Split Down' : 'Split Right'}
|
||||
</MenuItem>
|
||||
</GoodTooltip>
|
||||
|
||||
<ListDivider />
|
||||
|
||||
{/*<ListItem>*/}
|
||||
{/* <Typography level='body-sm'>*/}
|
||||
{/* Conversation*/}
|
||||
|
||||
@@ -3,7 +3,6 @@ import * as React from 'react';
|
||||
import { FormControl, Typography } from '@mui/joy';
|
||||
import AddAPhotoIcon from '@mui/icons-material/AddAPhoto';
|
||||
import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
|
||||
import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
|
||||
|
||||
import { FormLabelStart } from '~/common/components/forms/FormLabelStart';
|
||||
import { FormSwitchControl } from '~/common/components/forms/FormSwitchControl';
|
||||
@@ -19,7 +18,6 @@ export function UxLabsSettings() {
|
||||
const {
|
||||
labsAttachScreenCapture, setLabsAttachScreenCapture,
|
||||
labsCameraDesktop, setLabsCameraDesktop,
|
||||
labsSplitBranching, setLabsSplitBranching,
|
||||
} = useUXLabsStore();
|
||||
|
||||
return <>
|
||||
@@ -34,15 +32,11 @@ export function UxLabsSettings() {
|
||||
checked={labsCameraDesktop} onChange={setLabsCameraDesktop}
|
||||
/>}
|
||||
|
||||
<FormSwitchControl
|
||||
title={<><VerticalSplitIcon color={labsSplitBranching ? 'primary' : undefined} sx={{ mr: 0.25 }} /> Split Branching</>} description={/*'v1.6 · ' +*/ (labsSplitBranching ? 'Enabled' : 'Disabled')}
|
||||
checked={labsSplitBranching} onChange={setLabsSplitBranching}
|
||||
/>
|
||||
|
||||
<FormControl orientation='horizontal' sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<FormLabelStart title='Graduated' description='Ex-labs' />
|
||||
<Typography level='body-xs'>
|
||||
<Link href='https://github.com/enricoros/big-AGI/issues/359' target='_blank'>Draw App</Link>
|
||||
<Link href='https://github.com/enricoros/big-AGI/issues/208' target='_blank'>Split Chats</Link>
|
||||
{' · '}<Link href='https://github.com/enricoros/big-AGI/issues/359' target='_blank'>Draw App</Link>
|
||||
{' · '}<Link href='https://github.com/enricoros/big-AGI/issues/354' target='_blank'>Call AGI</Link>
|
||||
{' · '}<Link href='https://github.com/enricoros/big-AGI/issues/282' target='_blank'>Persona Creator</Link>
|
||||
{' · '}<Link href='https://github.com/enricoros/big-agi/issues/192' target='_blank'>Auto Diagrams</Link>
|
||||
|
||||
@@ -18,9 +18,6 @@ interface UXLabsStore {
|
||||
labsCameraDesktop: boolean;
|
||||
setLabsCameraDesktop: (labsCameraDesktop: boolean) => void;
|
||||
|
||||
labsSplitBranching: boolean;
|
||||
setLabsSplitBranching: (labsSplitBranching: boolean) => void;
|
||||
|
||||
}
|
||||
|
||||
export const useUXLabsStore = create<UXLabsStore>()(
|
||||
@@ -33,9 +30,6 @@ export const useUXLabsStore = create<UXLabsStore>()(
|
||||
labsCameraDesktop: false,
|
||||
setLabsCameraDesktop: (labsCameraDesktop: boolean) => set({ labsCameraDesktop }),
|
||||
|
||||
labsSplitBranching: false,
|
||||
setLabsSplitBranching: (labsSplitBranching: boolean) => set({ labsSplitBranching }),
|
||||
|
||||
}),
|
||||
{
|
||||
name: 'app-ux-labs',
|
||||
|
||||
Reference in New Issue
Block a user