diff --git a/.gitignore b/.gitignore index 8bdb39f25..17476507c 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ tmp.* **/.vscode **/.DS_Store .idea +**/Session.vim # "sensitive" data (i.e. raw zID) -backend/data/scrapers/enrolmentDataRaw.json \ No newline at end of file +backend/data/scrapers/enrolmentDataRaw.json diff --git a/frontend/src/components/CourseDescriptionPanel/CourseDescriptionPanel.tsx b/frontend/src/components/CourseDescriptionPanel/CourseDescriptionPanel.tsx index e7c42c32f..1a39df01f 100644 --- a/frontend/src/components/CourseDescriptionPanel/CourseDescriptionPanel.tsx +++ b/frontend/src/components/CourseDescriptionPanel/CourseDescriptionPanel.tsx @@ -159,4 +159,4 @@ const CourseDescriptionPanel = ({ ); }; -export default CourseDescriptionPanel; +export default React.memo(CourseDescriptionPanel); diff --git a/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx b/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx index 0db2c7e9f..4eda84c13 100644 --- a/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx +++ b/frontend/src/pages/CourseSelector/CourseMenu/CourseMenu.tsx @@ -202,4 +202,4 @@ const CourseMenu = ({ structure }: Props) => { ); }; -export default CourseMenu; +export default React.memo(CourseMenu); diff --git a/frontend/src/pages/CourseSelector/CourseMenu/styles.ts b/frontend/src/pages/CourseSelector/CourseMenu/styles.ts index c216ce9b6..b47556104 100644 --- a/frontend/src/pages/CourseSelector/CourseMenu/styles.ts +++ b/frontend/src/pages/CourseSelector/CourseMenu/styles.ts @@ -5,6 +5,7 @@ const SidebarWrapper = styled.div` overflow: auto; overflow-x: hidden; height: 100%; + width: 100%; border-right: 1px solid ${({ theme }) => theme.courseMenu?.borderColor}; `; diff --git a/frontend/src/pages/CourseSelector/CourseSelector.tsx b/frontend/src/pages/CourseSelector/CourseSelector.tsx index d5300db91..a247e2691 100644 --- a/frontend/src/pages/CourseSelector/CourseSelector.tsx +++ b/frontend/src/pages/CourseSelector/CourseSelector.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import axios from 'axios'; import { Structure } from 'types/api'; @@ -55,18 +55,50 @@ const CourseSelector = () => { if (programCode) fetchStructure(); }, [programCode, specs]); + const divRef = useRef(null); + const [menuOffset, setMenuOffset] = useState(undefined); + useEffect(() => { + const minMenuWidth = 100; + const maxMenuWidth = (60 * window.innerWidth) / 100; + const resizerDiv = divRef.current as HTMLDivElement; + const setNewWidth = (clientX: number) => { + if (clientX > minMenuWidth && clientX < maxMenuWidth) { + resizerDiv.style.left = `${clientX}px`; + setMenuOffset(clientX); + } + }; + const handleResize = (ev: globalThis.MouseEvent) => { + setNewWidth(ev.clientX); + }; + const endResize = (ev: MouseEvent) => { + setNewWidth(ev.clientX); + window.removeEventListener('mousemove', handleResize); + window.removeEventListener('mouseup', endResize); // remove myself + }; + const startResize = (ev: MouseEvent) => { + ev.preventDefault(); // stops highlighting text + window.addEventListener('mousemove', handleResize); + window.addEventListener('mouseup', endResize); + }; + resizerDiv?.addEventListener('mousedown', startResize); + return () => resizerDiv?.removeEventListener('mousedown', startResize); + }, []); + + const onCourseClick = useCallback((code: string) => dispatch(addTab(code)), [dispatch]); + return ( - + + {courseCode ? (
dispatch(addTab(code))} + onCourseClick={onCourseClick} courseDescInfoCache={courseDescInfoCache} />
diff --git a/frontend/src/pages/CourseSelector/styles.ts b/frontend/src/pages/CourseSelector/styles.ts index 350921f8f..5dbbe9c51 100644 --- a/frontend/src/pages/CourseSelector/styles.ts +++ b/frontend/src/pages/CourseSelector/styles.ts @@ -6,12 +6,23 @@ const ContainerWrapper = styled.div` height: calc(100vh - var(--navbar-height)); `; -const ContentWrapper = styled.div` +const ContentWrapper = styled.div<{ offset?: number }>` display: grid; - grid-template-columns: 20vw auto; + grid-template-columns: ${({ offset }) => (offset ? `${offset}px` : '20vw')} auto; height: var(--cs-bottom-cont-height); `; +const ContentResizer = styled.div<{ offset?: number }>` + cursor: col-resize; + height: 100%; + width: 6px; + background-color: transparent; + position: fixed; + left: ${({ offset }) => (offset ? `${offset}px` : '20vw')}; + margin-left: -3px; + z-index: 100; +`; + const InfographicContainer = styled.div` @keyframes fadeIn { 0% { @@ -40,4 +51,4 @@ const InfographicContainer = styled.div` } `; -export default { ContainerWrapper, ContentWrapper, InfographicContainer }; +export default { ContainerWrapper, ContentResizer, ContentWrapper, InfographicContainer };