Fix mobile / desktop navigation

This commit is contained in:
James Ketr 2025-04-17 21:30:45 -07:00
parent 9722da5038
commit 8209f4f0f9
2 changed files with 159 additions and 66 deletions

View File

@ -1,5 +1,5 @@
div {
box-sizing: border-box
box-sizing: border-box;
}
.TabPanel {
@ -68,22 +68,27 @@ div {
box-sizing: border-box;
overflow-x: visible;
min-width: 10rem;
width: 100%;
flex-grow: 1;
}
/* Prevent toolbar from shrinking vertically when media < 600px */
.MuiToolbar-root {
min-height: 56px !important;
padding-left: 16px !important;
padding-right: 16px !important;
.MenuCard.MuiCard-root {
display: flex;
flex-direction: column;
min-width: 10rem;
flex-grow: 1;
background-color: #1A2536; /* Midnight Blue */
color: #D3CDBF; /* Warm Gray */
border-radius: 0;
}
@media (min-width: 768px) {
.Controls {
width: 600px; /* or whatever you prefer for a desktop */
max-width: 80vw; /* Optional: Prevent it from taking up too much space */
.MenuCard.MuiCard-root button {
min-height: 64px;
}
/* Prevent toolbar from shrinking vertically when media < 600px */
.MuiToolbar-root {
min-height: 72px !important;
padding-left: 16px !important;
padding-right: 16px !important;
}
.Conversation {

View File

@ -1,5 +1,7 @@
import React, { useState, useEffect, useRef, useCallback, ReactElement } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import FormGroup from '@mui/material/FormGroup';
import Card from '@mui/material/Card';
import FormControlLabel from '@mui/material/FormControlLabel';
import { styled } from '@mui/material/styles';
import Avatar from '@mui/material/Avatar';
@ -21,13 +23,13 @@ import AppBar from '@mui/material/AppBar';
import Drawer from '@mui/material/Drawer';
import Toolbar from '@mui/material/Toolbar';
import SettingsIcon from '@mui/icons-material/Settings';
import CloseIcon from '@mui/icons-material/Close';
import IconButton from '@mui/material/IconButton';
import Box from '@mui/material/Box';
import CssBaseline from '@mui/material/CssBaseline';
import ResetIcon from '@mui/icons-material/History';
import SendIcon from '@mui/icons-material/Send';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import MenuIcon from '@mui/icons-material/Menu';
import PropagateLoader from "react-spinners/PropagateLoader";
@ -320,8 +322,8 @@ const App = () => {
const [processing, setProcessing] = useState(false);
const [sessionId, setSessionId] = useState<string | undefined>(undefined);
const [connectionBase,] = useState<string>(getConnectionBase(window.location))
const [mobileOpen, setMobileOpen] = useState(false);
const [isClosing, setIsClosing] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const [isMenuClosing, setIsMenuClosing] = useState(false);
const [snackOpen, setSnackOpen] = useState(false);
const [snackMessage, setSnackMessage] = useState("");
const [snackSeverity, setSnackSeverity] = useState<SeverityType>("success");
@ -343,6 +345,8 @@ const App = () => {
const [resume, setResume] = useState<MessageData | undefined>(undefined);
const [facts, setFacts] = useState<MessageData | undefined>(undefined);
const timerRef = useRef<any>(null);
const isDesktop = useMediaQuery('(min-width:600px)');
const prevIsDesktopRef = useRef<boolean>(isDesktop);
const startCountdown = (seconds: number) => {
if (timerRef.current) clearInterval(timerRef.current);
@ -400,6 +404,17 @@ const App = () => {
setSnackOpen(true);
}, []);
useEffect(() => {
if (prevIsDesktopRef.current === isDesktop)
return;
if (menuOpen) {
setMenuOpen(false);
}
prevIsDesktopRef.current = isDesktop;
}, [isDesktop, setMenuOpen, menuOpen])
// Get the system information
useEffect(() => {
if (systemInfo !== undefined || sessionId === undefined) {
@ -810,28 +825,76 @@ const App = () => {
}
};
const handleDrawerClose = () => {
setIsClosing(true);
setMobileOpen(false);
const handleMenuClose = () => {
setIsMenuClosing(true);
setMenuOpen(false);
};
const handleDrawerTransitionEnd = () => {
setIsClosing(false);
const handleMenuTransitionEnd = () => {
setIsMenuClosing(false);
};
const handleDrawerToggle = () => {
if (!isClosing) {
setMobileOpen(!mobileOpen);
const handleMenuToggle = () => {
if (!isMenuClosing) {
setMenuOpen(!menuOpen);
}
};
const drawer = (
const settingsPanel = (
<>
{sessionId !== undefined && systemInfo !== undefined &&
<Controls {...{ messageHistoryLength, setMessageHistoryLength, tools, rags, reset, systemPrompt, toggleTool, toggleRag, setSystemPrompt, systemInfo }} />}
</>
);
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
setTab(newValue);
};
const menuDrawer = (
<Card className="MenuCard">
<Tabs sx={{ display: "flex", flexGrow: 1 }}
orientation="vertical"
value={tab}
indicatorColor="secondary"
textColor="inherit"
variant="scrollable"
allowScrollButtonsMobile
onChange={handleTabChange}
aria-label="Backstory navigation">
<Tab sx={{ fontSize: '1rem' }} label="Backstory"
value={0}
icon={
<Avatar sx={{
width: 24,
height: 24
}}
variant="rounded"
alt="Backstory logo"
src="/logo192.png" />
}
iconPosition="start" />
<Tab
value={1}
sx={{ fontSize: '1rem' }} wrapped
label="Resume Builder"
/>
<Tab
value={2}
sx={{ fontSize: '1rem' }} wrapped
label="Context Visualizer"
/>
<Tab
value={3}
sx={{ fontSize: '1rem' }} label="About" />
<Tab
value={4}
sx={{ fontSize: '1rem' }} icon={<SettingsIcon />} />
</Tabs>
</Card>
);
const submitQuery = (text: string) => {
sendQuery(text);
}
@ -1037,10 +1100,6 @@ const App = () => {
setSnackOpen(false);
};
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
setTab(newValue);
};
/* toolbar height is 56px + 8px margin-top */
const Offset = styled('div')(({ theme }) => ({ ...theme.mixins.toolbar, minHeight: '64px', height: '64px' }));
@ -1056,44 +1115,66 @@ const App = () => {
>
<Toolbar>
{
mobileOpen === false &&
<Box sx={{ display: "flex", flexGrow: 1 }}>
<Tabs value={tab} indicatorColor="secondary"
textColor="inherit"
variant="scrollable"
allowScrollButtonsMobile
onChange={handleTabChange} aria-label="Backstory navigation">
<Tab label="Backstory" icon={<Avatar sx={{ width: 24, height: 24 }} variant="rounded" alt="Backstory logo" src="/logo192.png" />} iconPosition="start" />
<Tab wrapped label="Resume Builder" />
<Tab wrapped label="Context Visualizer" />
<Tab label="About" />
</Tabs>
<Tooltip title="LLM Settings">
<IconButton
color="inherit"
aria-label="open drawer"
edge="end"
onClick={handleDrawerToggle}
>
<SettingsIcon />
</IconButton>
</Tooltip>
</Box>
}
<Box sx={{ display: "flex", flexGrow: 1, flexDirection: "row" }}>
{
mobileOpen === true &&
<Tooltip title="Close Settings">
!isDesktop &&
<IconButton
sx={{ display: "flex", margin: 'auto 0px' }}
size="large"
edge="start"
color="inherit"
aria-label="close drawer"
edge="end"
onClick={handleDrawerToggle}
sx={{ mr: 2, right: 0, position: "absolute" }}
onClick={handleMenuToggle}
>
<CloseIcon />
</IconButton>
<Tooltip title="Navigation">
<MenuIcon />
</Tooltip>
</IconButton>
}
{ menuOpen === false &&
<Tabs sx={{ display: "flex", flexGrow: 1 }}
value={tab}
indicatorColor="secondary"
textColor="inherit"
variant="fullWidth"
allowScrollButtonsMobile
onChange={handleTabChange}
aria-label="Backstory navigation">
<Tab sx={{ fontSize: '1rem' }} label="Backstory"
value={0}
icon={
<Avatar sx={{
width: 24,
height: 24
}}
variant="rounded"
alt="Backstory logo"
src="/logo192.png" />
}
iconPosition="start" />
{ isDesktop &&
<Tab
value={1}
sx={{ fontSize: '1rem' }} wrapped
label="Resume Builder"
/>
}
{isDesktop &&
<Tab
value={2}
sx={{ fontSize: '1rem' }} wrapped
label="Context Visualizer"
/>
}
<Tab
value={3}
sx={{ fontSize: '1rem' }} label="About" />
<Tab
value={4}
sx={{ flexShrink: 1, flexGrow: 0, fontSize: '1rem' }} icon={<SettingsIcon />}/>
</Tabs>
}
</Box>
}
</Toolbar>
@ -1106,13 +1187,12 @@ const App = () => {
component="nav"
aria-label="mailbox folders"
>
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Drawer
container={window.document.body}
variant="temporary"
open={mobileOpen}
onTransitionEnd={handleDrawerTransitionEnd}
onClose={handleDrawerClose}
open={menuOpen}
onTransitionEnd={handleMenuTransitionEnd}
onClose={handleMenuClose}
sx={{
display: 'block',
'& .MuiDrawer-paper': { boxSizing: 'border-box' },
@ -1124,7 +1204,7 @@ const App = () => {
}}
>
<Toolbar />
{drawer}
{menuDrawer}
</Drawer>
</Box>
@ -1203,6 +1283,14 @@ const App = () => {
</Box>
</CustomTabPanel>
<CustomTabPanel tab={tab} index={4}>
<Box className="ChatBox">
<Box className="Conversation">
{ settingsPanel }
</Box>
</Box>
</CustomTabPanel>
</Box>
<Snackbar open={snackOpen} autoHideDuration={(snackSeverity === "success" || snackSeverity === "info") ? 1500 : 6000} onClose={handleSnackClose}>