diff --git a/client/src/App.tsx b/client/src/App.tsx index 1a6868c1d..694ae4d9e 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -2,7 +2,7 @@ import { Box, Button, GlobalStyles, StyledEngineProvider, ThemeProvider } from ' import { styled } from '@mui/system'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import React, { useContext, useEffect } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { Outlet } from 'react-router-dom'; import getCourseInfo from './api/getCourseInfo'; @@ -99,6 +99,8 @@ const ICSButton = styled(Button)` `; const App: React.FC = () => { + + const [collapsed, setCollapsed] = useState(false); const { themeObject, currentTheme, @@ -638,7 +640,7 @@ const App: React.FC = () => { - + { {groupsSidebarCollapsed ? ( <> - + ) : ( diff --git a/client/src/components/controls/Controls.tsx b/client/src/components/controls/Controls.tsx index 065fa3be3..5f090fde2 100644 --- a/client/src/components/controls/Controls.tsx +++ b/client/src/components/controls/Controls.tsx @@ -1,4 +1,4 @@ -import { Box, Grid } from '@mui/material'; +import { Box } from '@mui/material'; import { styled } from '@mui/system'; import React from 'react'; @@ -6,44 +6,29 @@ import { ControlsProps } from '../../interfaces/PropTypes'; import Autotimetabler from './Autotimetabler'; import CourseSelect from './CourseSelect'; import CustomEvents from './CustomEvent'; -import History from './History'; import TermSelect from './TermSelect'; +const ControlsBar = styled(Box)` + display: flex; + align-items: flex-end; + padding-left: 66px; + gap: 12px; +`; const TermSelectWrapper = styled(Box)` - flex: 0 0 auto; - margin-top: 20px; - margin-right: 10px; min-width: 140px; - display: flex; - align-items: flex-start; + margin-bottom: 0; `; const SelectWrapper = styled(Box)` - display: flex; - flex-direction: row; - grid-column: 1 / -1; - grid-row: 1; - padding-top: 20px; - flex-grow: 1; - flex-shrink: 1; - flex-basis: 0; + flex-grow: 2; + min-width: 600px; + margin-bottom: 0; `; -const AutotimetablerWrapper = styled(Box)` - flex: 1; - - ${({ theme }) => theme.breakpoints.down('sm')} { - flex: none; - } -`; - -const CustomEventsWrapper = styled(Box)` - flex: 1; -`; - -const HistoryWrapper = styled(Box)` - margin-top: 20px; - margin-left: 3px; +const ButtonRow = styled(Box)` + display: flex; + gap: 8px; + margin-bottom: 0; `; const Controls: React.FC = ({ @@ -53,33 +38,23 @@ const Controls: React.FC = ({ handleRemoveCourse, }) => { return ( - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + ); }; -export default Controls; +export default Controls; \ No newline at end of file diff --git a/client/src/components/controls/History.tsx b/client/src/components/controls/History.tsx index 4afb53420..512fbb4f4 100644 --- a/client/src/components/controls/History.tsx +++ b/client/src/components/controls/History.tsx @@ -1,5 +1,6 @@ import { Delete, Redo, Undo } from '@mui/icons-material'; import { IconButton, Tooltip } from '@mui/material'; +import { Box } from '@mui/material'; import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { AppContext } from '../../context/AppContext'; @@ -31,7 +32,7 @@ const History: React.FC = () => { useContext(CourseContext); const { isDrag, setIsDrag, selectedTimetable, setSelectedTimetable, displayTimetables, setDisplayTimetables, term } = useContext(AppContext); - const { user } = useContext(UserContext); + const { user, groupsSidebarCollapsed } = useContext(UserContext); const timetableActions = useRef({}); const actionsPointer = useRef({}); @@ -332,46 +333,52 @@ const History: React.FC = () => { disableConfirm={disableReset.all} confirmButtonId="confirm-delete-button" /> - - { - setClearOpen(true); - }} - size="large" - > - - - - - + + { - changeHistory(-1); + setClearOpen(true); }} - size="large" + size={!groupsSidebarCollapsed ? 'small' : 'large'} > - + - - - - - { - changeHistory(1); - }} - size="large" - > - - - - + + + + { + changeHistory(-1); + }} + size={!groupsSidebarCollapsed ? 'small' : 'large'} + > + + + + + + + { + changeHistory(1); + }} + size={!groupsSidebarCollapsed ? 'small' : 'large'} + > + + + + + ); }; diff --git a/client/src/components/sidebar/Sidebar.tsx b/client/src/components/sidebar/Sidebar.tsx index 82ad2a024..417048cfc 100644 --- a/client/src/components/sidebar/Sidebar.tsx +++ b/client/src/components/sidebar/Sidebar.tsx @@ -169,21 +169,23 @@ const modalData = [ }, ]; -const Sidebar: React.FC = () => { +interface SidebarProps { + collapsed: boolean; + setCollapsed: (val: boolean) => void; +} + +const Sidebar: React.FC = ({ collapsed, setCollapsed }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); const collapsedWidth = useMemo(() => (isMobile ? 0 : 80), [isMobile]); const isWide = useMediaQuery(theme.breakpoints.only('xl')); const [currLogo, setCurrLogo] = useState(notanglesLogo); - const [collapsed, setCollapsed] = useState(() => !isWide); const { groupsSidebarCollapsed } = useContext(UserContext); const handleCollapse = (val: boolean) => { setCollapsed(val); - // forces window resize event upon sidebar state changing to adjust position of cards - // Not currently used, but here is how you would do it if needed - // setTimeout(() => window.dispatchEvent(new Event('resize')), 120); + }; const modalComponents = useMemo( diff --git a/client/src/components/timetableTabs/TimetableTabs.tsx b/client/src/components/timetableTabs/TimetableTabs.tsx index ed0371e91..b21071311 100644 --- a/client/src/components/timetableTabs/TimetableTabs.tsx +++ b/client/src/components/timetableTabs/TimetableTabs.tsx @@ -26,8 +26,13 @@ import { } from '../../styles/TimetableTabStyles'; import storage from '../../utils/storage'; import TimetableTabContextMenu from './TimetableTabContextMenu'; +import History from '../controls/History'; -const TimetableTabs: React.FC = () => { +interface TimetableTabsProps { + collapsed: boolean; +} + +const TimetableTabs: React.FC = ({ collapsed }) => { const TIMETABLE_LIMIT = 13; const { @@ -57,7 +62,7 @@ const TimetableTabs: React.FC = () => { setTabTheme(isDarkMode ? tabThemeDark : tabThemeLight); }, [isDarkMode]); - // Helper function to set the timetable state + const setTimetableState = ( selectedCourses: CourseData[], selectedClasses: SelectedClasses, @@ -72,9 +77,7 @@ const TimetableTabs: React.FC = () => { setSelectedTimetable(timetableIndex); }; - /** - * Timetable handlers - */ + // Creates new timetable const handleCreateTimetable = () => { if (!term) return; @@ -105,9 +108,7 @@ const TimetableTabs: React.FC = () => { } }; - /** - * Drag and drop functions for rearranging timetable tabs - */ + // Handles timetable switching by updating the selected courses, classes and events to the new timetable const handleSwitchTimetables = (timetables: TimetableData[], timetableIndex: number) => { const { selectedCourses, selectedClasses, createdEvents, assignedColors } = timetables[timetableIndex]; @@ -141,9 +142,7 @@ const TimetableTabs: React.FC = () => { handleSwitchTimetables(newTimetables, destination.index); }; - /** - * Dropdown menu tab handlers - */ + // Left click handler for the three dots icon (editing the timetable tab) const handleMenuClick = (e: React.MouseEvent) => { e.preventDefault(); @@ -160,67 +159,77 @@ const TimetableTabs: React.FC = () => { setAnchorElement({ x: event.clientX, y: event.clientY }); }; + return ( - - - - - {(props) => ( - - {Object.keys(displayTimetables).length > 0 && term && displayTimetables[term] - ? displayTimetables[term]?.map((timetable: TimetableData, index: number) => ( - - {(props) => { - if (props.draggableProps.style?.transform) { - const horizShift = props.draggableProps.style?.transform.match(/(-?\d+)/g)?.map(Number)![0]; - // forcing horizontal movement - props.draggableProps.style.transform = `translate(${horizShift ? horizShift : 0}px, 0)`; - } - return ( - { - handleSwitchTimetables(displayTimetables[term], index); - }} - onContextMenu={(e) => { - handleRightTabClick(e, index); - }} - ref={props.innerRef} - {...props.draggableProps} - {...props.dragHandleProps} - sx={TabStyle(index, selectedTimetable)} - > - {displayTimetables[term][index].isPrimary && ( - - - - )} - {timetable.name} - {selectedTimetable === index ? ( - - - - ) : ( - <> - )} - - ); - }} - - )) - : null} - {props.placeholder} - - )} - - - - - - - - - - + + + 5)} + > + + + + {(props) => ( + + {Object.keys(displayTimetables).length > 0 && term && displayTimetables[term] + ? displayTimetables[term]?.map((timetable: TimetableData, index: number) => ( + + {(props) => { + if (props.draggableProps.style?.transform) { + const horizShift = props.draggableProps.style?.transform.match(/(-?\d+)/g)?.map(Number)![0]; + props.draggableProps.style.transform = `translate(${horizShift ? horizShift : 0}px, 0)`; + } + return ( + { + handleSwitchTimetables(displayTimetables[term], index); + }} + onContextMenu={(e) => { + handleRightTabClick(e, index); + }} + ref={props.innerRef} + {...props.draggableProps} + {...props.dragHandleProps} + sx={TabStyle(index, selectedTimetable)} + > + {displayTimetables[term][index].isPrimary && ( + + + + )} + {timetable.name} + {selectedTimetable === index ? ( + + + + ) : ( + <> + )} + + ); + }} + + )) + : null} + {props.placeholder} + + )} + + + + + + + + + + + + + + + ); }; export { TimetableTabs }; diff --git a/client/src/styles/TimetableTabStyles.tsx b/client/src/styles/TimetableTabStyles.tsx index 9210d86a5..b8aa26cb7 100644 --- a/client/src/styles/TimetableTabStyles.tsx +++ b/client/src/styles/TimetableTabStyles.tsx @@ -34,10 +34,17 @@ export const StyledSnackbar = styled(Snackbar)(({ theme }) => ({ }, })); -export const TabsSection = styled(Box)` +export const TabsSection = styled(Box, { shouldForwardProp: (prop) => prop !== 'shouldScroll' })< + BoxProps & { shouldScroll?: boolean } +>` padding-top: 20px; margin-left: 66px; - overflow: auto; + ${(props) => props.shouldScroll ? ` + overflow: auto; + max-width: calc(100vw - 200px); /* Adjust based on your layout */ + ` : ` + overflow: visible; + `} &::-webkit-scrollbar { height: 5px; }