Skip to content

Commit

Permalink
fix: Improve UX for mobile user (Chainlit#479)
Browse files Browse the repository at this point in the history
* fix: Improve UX for mobile user

---------

Co-authored-by: Willy Douhard <[email protected]>
  • Loading branch information
alimtunc and willydouhard authored Oct 17, 2023
1 parent ba93c76 commit 8747400
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 57 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@typescript-eslint/no-explicit-any": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn", // or "error"
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
Expand Down
3 changes: 2 additions & 1 deletion cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ export default defineConfig({
bundler: 'vite'
}
},
viewportWidth: 1200,

e2e: {
supportFile: false,
defaultCommandTimeout: 10000,
video: false,
baseUrl: 'http://127.0.0.1:8000',
setupNodeEvents(on, config) {
setupNodeEvents(on) {
on('task', {
log(message) {
console.log(message);
Expand Down
7 changes: 5 additions & 2 deletions cypress/e2e/conversations/spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ describe('Conversations', () => {
cy.intercept('GET', '/project/settings', {
statusCode: 200,
body: {
ui: {},
ui: {
show_readme_as_default: true
},
userEnv: [],
dataPersistence: true,
markdown: 'foo'
markdown: 'foo',
chatProfiles: []
}
}).as('getSettings');

Expand Down
23 changes: 15 additions & 8 deletions frontend/src/components/organisms/chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ const Chat = () => {
[askUser, user, replyMessage]
);

const tasklist = tasklists.at(-1);
const enableMultiModalUpload = !disabled && pSettings?.features.multi_modal;
const tasklist = tasklists[tasklists.length - 1];
const enableMultiModalUpload = !disabled && pSettings?.features?.multi_modal;

return (
<Box
Expand All @@ -156,17 +156,24 @@ const Chat = () => {
</>
) : null}
<SideView>
<TaskList tasklist={tasklist} isMobile={true} />

<Box my={1} />
{error && (
<Alert id="session-error" severity="error">
Could not reach the server.
</Alert>
<Box
sx={{
width: '100%',
maxWidth: '60rem',
mx: 'auto',
my: 2
}}
>
<Alert sx={{ mx: 2 }} id="session-error" severity="error">
Could not reach the server.
</Alert>
</Box>
)}
<TaskList tasklist={tasklist} isMobile={true} />
<ErrorBoundary>
<ChatProfiles />

{!messages.length && pSettings?.ui.show_readme_as_default ? (
<WelcomeScreen />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const UploadButton = ({
options: { noDrag: true }
});

if (!upload || !pSettings?.features.multi_modal) return null;
if (!upload || !pSettings?.features?.multi_modal) return null;
const { getRootProps, getInputProps, uploading } = upload;

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useRecoilState } from 'recoil';

import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';

import { settingsState } from 'state/settings';

const OpenChatHistoryButton = ({ mode }: { mode: 'mobile' | 'desktop' }) => {
const [settings, setSettings] = useRecoilState(settingsState);
const isDesktop = mode === 'desktop';

return !settings.isChatHistoryOpen ? (
<Box
sx={
isDesktop
? {
zIndex: 1,
mt: 1,
ml: 1,
display: 'none',
'@media (min-width: 66rem)': {
position: 'absolute',
display: 'block'
}
}
: {}
}
>
<IconButton
sx={{
borderRadius: isDesktop ? 1 : 8,
backgroundColor: (theme) => theme.palette.background.paper
}}
onClick={() =>
setSettings((prev) => ({
...prev,
isChatHistoryOpen: true
}))
}
>
<KeyboardDoubleArrowRightIcon />
</IconButton>
</Box>
) : null;
};

export default OpenChatHistoryButton;
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { useEffect, useRef, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';

import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft';
import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
import Box from '@mui/material/Box';
import Drawer from '@mui/material/Drawer';
import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
Expand All @@ -20,6 +18,7 @@ import {
conversationsHistoryState
} from 'state/conversations';
import { projectSettingsState } from 'state/project';
import { settingsState } from 'state/settings';
import { accessTokenState } from 'state/user';

import { ConversationsHistoryList } from './ConversationsHistoryList';
Expand All @@ -31,15 +30,15 @@ const BATCH_SIZE = 20;
let _scrollTop = 0;

const _ConversationsHistorySidebar = () => {
const isMobile = useMediaQuery('(max-width:800px)');
const isMobile = useMediaQuery('(max-width:66rem)');

const [conversations, setConversations] = useRecoilState(
conversationsHistoryState
);
const accessToken = useRecoilValue(accessTokenState);
const filters = useRecoilValue(conversationsFiltersState);
const [settings, setSettings] = useRecoilState(settingsState);

const [open, setOpen] = useState(true);
const [shouldLoadMore, setShouldLoadMore] = useState(false);
const [error, setError] = useState<string | undefined>(undefined);
const [prevFilters, setPrevFilters] =
Expand Down Expand Up @@ -98,10 +97,17 @@ const _ConversationsHistorySidebar = () => {
}
};

const setChatHistoryOpen = (open: boolean) =>
setSettings((prev) => ({ ...prev, isChatHistoryOpen: open }));

useEffect(() => {
if (ref.current) {
ref.current.scrollTop = _scrollTop;
}

if (isMobile) {
setChatHistoryOpen(false);
}
}, []);

useEffect(() => {
Expand Down Expand Up @@ -135,15 +141,15 @@ const _ConversationsHistorySidebar = () => {
<Drawer
className="chat-history-drawer"
anchor="left"
open={open}
open={settings.isChatHistoryOpen}
variant={isMobile ? 'temporary' : 'persistent'}
hideBackdrop
PaperProps={{
ref: ref,
onScroll: handleScroll
}}
sx={{
width: open ? DRAWER_WIDTH : 0,
width: settings.isChatHistoryOpen ? DRAWER_WIDTH : 0,
'& .MuiDrawer-paper': {
position: 'inherit',
gap: 1,
Expand Down Expand Up @@ -171,8 +177,8 @@ const _ConversationsHistorySidebar = () => {
>
Chat History
</Typography>
<IconButton edge="end" onClick={() => setOpen(false)}>
<KeyboardDoubleArrowLeftIcon sx={{ color: 'grey.500' }} />
<IconButton edge="end" onClick={() => setChatHistoryOpen(false)}>
<KeyboardDoubleArrowLeftIcon sx={{ color: 'text.primary' }} />
</IconButton>
</Stack>
<Filters />
Expand All @@ -186,25 +192,6 @@ const _ConversationsHistorySidebar = () => {
/>
) : null}
</Drawer>
<Box
sx={{
position: 'absolute',
mt: 1,
ml: 1,
zIndex: !open ? 1 : -1,
opacity: !open ? 1 : 0
}}
>
<IconButton
sx={{
borderRadius: 1,
backgroundColor: (theme) => theme.palette.background.paper
}}
onClick={() => setOpen(true)}
>
<KeyboardDoubleArrowRightIcon />
</IconButton>
</Box>
</>
);
};
Expand Down
32 changes: 20 additions & 12 deletions frontend/src/components/organisms/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import {
IconButton,
Menu,
Stack,
Theme,
Toolbar,
useTheme
Toolbar
} from '@mui/material';
import useMediaQuery from '@mui/material/useMediaQuery';

Expand All @@ -23,8 +21,12 @@ import UserButton from 'components/atoms/buttons/userButton';
import { Logo } from 'components/atoms/logo';
import NewChatButton from 'components/molecules/newChatButton';

import { useAuth } from 'hooks/auth';

import { projectSettingsState } from 'state/project';

import OpenChatHistoryButton from './conversationsHistory/sidebar/OpenChatHistoryButton';

interface INavItem {
to: string;
label: string;
Expand Down Expand Up @@ -58,12 +60,13 @@ function NavItem({ to, label }: INavItem) {
}

interface NavProps {
dataPersistence?: boolean;
hasReadme?: boolean;
}

function Nav({ hasReadme }: NavProps) {
function Nav({ dataPersistence, hasReadme }: NavProps) {
const location = useLocation();
const theme = useTheme();
const { isAuthenticated } = useAuth();
const [open, setOpen] = useState(false);
const ref = useRef<any>();

Expand All @@ -73,16 +76,15 @@ function Nav({ hasReadme }: NavProps) {
anchorEl = ref.current;
}

const matches = useMediaQuery(theme.breakpoints.down('md'));

const isMobile = useMediaQuery('(max-width: 66rem)');
const tabs = [{ to: '/', label: 'Chat' }];

if (hasReadme) {
tabs.push({ to: '/readme', label: 'Readme' });
}

const nav = (
<Stack direction={matches ? 'column' : 'row'} spacing={1}>
<Stack direction={isMobile ? 'column' : 'row'} spacing={1}>
{tabs.map((t) => {
const active = location.pathname === t.to;
return (
Expand All @@ -94,7 +96,7 @@ function Nav({ hasReadme }: NavProps) {
</Stack>
);

if (matches) {
if (isMobile) {
return (
<>
<IconButton
Expand All @@ -105,6 +107,9 @@ function Nav({ hasReadme }: NavProps) {
>
<MenuIcon />
</IconButton>
{isAuthenticated && dataPersistence ? (
<OpenChatHistoryButton mode="mobile" />
) : null}
<Menu
autoFocus
anchorEl={anchorEl}
Expand Down Expand Up @@ -139,7 +144,7 @@ function Nav({ hasReadme }: NavProps) {

export default function Header() {
const pSettings = useRecoilValue(projectSettingsState);
const matches = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
const matches = useMediaQuery('(max-width: 66rem)');

return (
<AppBar elevation={0} color="transparent" position="static">
Expand All @@ -153,9 +158,12 @@ export default function Header() {
borderBottomColor: (theme) => theme.palette.divider
}}
>
<Stack alignItems="center" direction={'row'} gap={3}>
<Stack alignItems="center" direction={'row'} gap={!matches ? 3 : 1}>
{!matches ? <Logo style={{ maxHeight: '25px' }} /> : null}
<Nav hasReadme={!!pSettings?.markdown} />
<Nav
dataPersistence={pSettings?.dataPersistence}
hasReadme={!!pSettings?.markdown}
/>
</Stack>
<Stack
alignItems="center"
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/pages/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useRecoilValue } from 'recoil';
import { Alert, Box, Stack } from '@mui/material';

import { ConversationsHistorySidebar } from 'components/organisms/conversationsHistory/sidebar';
import OpenChatHistoryButton from 'components/organisms/conversationsHistory/sidebar/OpenChatHistoryButton';
import Header from 'components/organisms/header';

import { useAuth } from 'hooks/auth';
Expand Down Expand Up @@ -47,6 +48,7 @@ const Page = ({ children }: Props) => {
) : (
<Stack direction="row" height="100%" width="100%" overflow="auto">
<ConversationsHistorySidebar />
<OpenChatHistoryButton mode={'desktop'} />
{children}
</Stack>
)}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/state/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const defaultSettingsState = {
defaultCollapseContent: true,
expandAll: false,
hideCot: false,
isChatHistoryOpen: true,
theme
};

Expand All @@ -24,6 +25,7 @@ export const settingsState = atom<{
expandAll: boolean;
hideCot: boolean;
theme: ThemeVariant;
isChatHistoryOpen: boolean;
}>({
key: 'AppSettings',
default: defaultSettingsState
Expand Down
5 changes: 0 additions & 5 deletions libs/components/hooks/useChat/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,3 @@ export const firstUserMessageState = atom<IMessage | undefined>({
key: 'FirstUserMessage',
default: undefined
});

export const chatProfile = atom<string | undefined>({
key: 'ChatProfile',
default: undefined
});

0 comments on commit 8747400

Please sign in to comment.