diff --git a/site/src/App.scss b/site/src/App.scss index e961da41..2fbfe877 100644 --- a/site/src/App.scss +++ b/site/src/App.scss @@ -43,6 +43,80 @@ button { } } +.ppc-popover { + border-radius: 8px; + padding: 0px; + box-shadow: none; + max-width: 375px; + top: -16px !important; + + $filter: drop-shadow(0px 0px 16px rgba(0, 0, 0, 0.35)); + filter: $filter; + -webkit-filter: $filter; + border: none; + + .popover-body { + border-radius: 8px; + padding: 16px; + } + + .arrow { + z-index: -1; + &::after { + display: none; + } + } + .arrow::before { + pointer-events: none; + position: absolute; + border: 8px solid transparent; + border-width: 12px 16px; + top: 8px; + left: unset; + } + &[data-popper-placement='bottom'] { + top: -24px !important; + .arrow::before { + left: 0; + bottom: 0; + top: 8px; + border-bottom-color: var(--overlay1); + transform: translate(-25%, -100%); + border-width: 16px 12px; + } + } + &[data-popper-placement='left-start'] { + .arrow::before { + left: -2px; + border-left-color: var(--overlay1); + } + } + &[data-popper-placement='right-start'] { + .arrow::before { + right: -2px; + border-right-color: var(--overlay1); + } + } +} + +.bs-popover-left { + margin-right: 20px; + + .arrow::after, + .arrow::before { + left: -1px; + } +} + +.bs-popover-bottom { + margin-top: 48px; + .arrow::after, + .arrow::before { + top: -12px; + left: 7px; + } +} + .ppc-modal { font-size: 18px; diff --git a/site/src/component/CoursePopover/CoursePopover.scss b/site/src/component/CoursePopover/CoursePopover.scss new file mode 100644 index 00000000..292ff8fa --- /dev/null +++ b/site/src/component/CoursePopover/CoursePopover.scss @@ -0,0 +1,62 @@ +.course-popover { + line-height: normal; + + .popover-name { + font-weight: bold; + color: var(--text-dark); + font-size: 16px; + height: 21px; + margin-top: -2px; + } + + .popover-subtitle { + font-weight: bold; + } + + .popover-units { + font-weight: normal; + } + + .popover-description { + font-size: 14px; + padding-top: 12px; + line-height: 17px; + } + + .popover-detail { + padding-top: 12px; + } + + .popover-detail-prefix { + font-weight: bold; + } + + .popover-detail-warning { + font-size: 14px; + color: #ce0000; + gap: 5px; + + .popover-detail-warning-icon { + margin-bottom: 4px; + margin-right: 4px; + font-size: 16px; + } + } + + .popover-detail-italics { + padding-top: 6px; + font-weight: 400; + font-size: 12px; + font-style: italic; + color: var(--petr-gray); + } +} + +[data-theme='dark'] { + .popover-detail-warning { + color: red; + } + .popover-detail-italics { + color: var(--petr-gray); + } +} diff --git a/site/src/component/CoursePopover/CoursePopover.tsx b/site/src/component/CoursePopover/CoursePopover.tsx new file mode 100644 index 00000000..2819ae35 --- /dev/null +++ b/site/src/component/CoursePopover/CoursePopover.tsx @@ -0,0 +1,68 @@ +import { FC } from 'react'; +import './CoursePopover.scss'; +import { ExclamationTriangle } from 'react-bootstrap-icons'; +import Popover from 'react-bootstrap/Popover'; + +interface CoursePopoverProps { + department: string; + courseNumber: string; + title: string; + minUnits: number; + maxUnits: number; + description: string; + prerequisiteText: string; + corequisites: string; + requiredCourses?: string[]; +} + +const CoursePopover: FC = (props) => { + const { + department, + courseNumber, + title, + minUnits, + maxUnits, + description, + prerequisiteText, + corequisites, + requiredCourses, + } = props; + + return ( + +
+ {department + ' ' + courseNumber + ' '} + ({minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`} units) +
+
+ {title + ':'} +
+ {description} +
+ {prerequisiteText && ( +
+ Prerequisites: {prerequisiteText} +
+ )} + {corequisites && ( +
+ Corequisites: {corequisites} +
+ )} + {requiredCourses && ( +
+
+ + Prerequisite{requiredCourses?.length > 1 ? 's' : ''} Not Met: {requiredCourses?.join(', ')} +
+
+ Already completed? Click "Transfer Credits" at the top of the roadmap viewer to add{' '} + {requiredCourses?.length > 1 ? 'these prerequisites' : 'this prerequisite'}. +
+
+ )} +
+ ); +}; + +export default CoursePopover; diff --git a/site/src/pages/RoadmapPage/Course.scss b/site/src/pages/RoadmapPage/Course.scss index 45f3814e..ab7dac70 100644 --- a/site/src/pages/RoadmapPage/Course.scss +++ b/site/src/pages/RoadmapPage/Course.scss @@ -66,35 +66,6 @@ color: red; } -.course-popover { - padding: 5%; - - .popover-name { - font-weight: bold; - color: var(--text-dark); - font-size: 16px; - } - - .popover-units { - color: #c4c4c4; - - .popover-units-value { - font-weight: bold; - } - } - - .popover-description { - padding-top: 5%; - } - - .popover-detail { - padding-top: 5%; - } - .popover-detail-prefix { - font-weight: bold; - } -} - .course-footer { height: auto; display: flex; diff --git a/site/src/pages/RoadmapPage/Course.tsx b/site/src/pages/RoadmapPage/Course.tsx index c1c84c75..06025b16 100644 --- a/site/src/pages/RoadmapPage/Course.tsx +++ b/site/src/pages/RoadmapPage/Course.tsx @@ -3,8 +3,10 @@ import './Course.scss'; import { Button } from 'react-bootstrap'; import { InfoCircle, ExclamationTriangle, Trash, BagPlus, BagFill } from 'react-bootstrap-icons'; import CourseQuarterIndicator from '../../component/QuarterTooltip/CourseQuarterIndicator'; +import CoursePopover from '../../component/CoursePopover/CoursePopover'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Popover from 'react-bootstrap/Popover'; +import { useIsMobile } from '../../helpers/util'; import { CourseGQLData } from '../../types/types'; import ThemeContext from '../../style/theme-context'; @@ -27,6 +29,7 @@ interface CourseProps extends CourseGQLData { onAddToBag?: () => void; isInBag?: boolean; removeFromBag?: () => void; + openPopoverLeft?: boolean; addMode?: 'tap' | 'drag'; } @@ -47,45 +50,13 @@ const Course: FC = (props) => { onAddToBag, isInBag, removeFromBag, + openPopoverLeft, } = props; - const CoursePopover = ( - - -
-
- {department + ' ' + courseNumber} {title} -
-
- {minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`}{' '} - units -
-
{description}
- {prerequisiteText && ( -
- Prerequisites: {prerequisiteText} -
- )} - {corequisites && ( -
- Corequisites: {corequisites} -
- )} -
-
-
- ); const dispatch = useAppDispatch(); - const warningPopover = ( - - - - - - ); - const courseRoute = '/course/' + props.department.replace(/\s+/g, '') + props.courseNumber.replace(/\s+/g, ''); + const isMobile = useIsMobile(); const insertCourseOnClick = () => { dispatch(setActiveCourse(props)); @@ -105,14 +76,28 @@ const Course: FC = (props) => { {minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`} unit{maxUnits === 1 ? '' : 's'} - - + + + + } + delay={100} + > +
{requiredCourses ? : }
- {requiredCourses && ( - - - - )}
{onDelete ? ( diff --git a/site/src/pages/RoadmapPage/SearchSidebar.tsx b/site/src/pages/RoadmapPage/SearchSidebar.tsx index bbf04115..fb228475 100644 --- a/site/src/pages/RoadmapPage/SearchSidebar.tsx +++ b/site/src/pages/RoadmapPage/SearchSidebar.tsx @@ -97,7 +97,7 @@ const SearchSidebar = () => { className={'search-body' + (isMobile ? ' disabled' : '')} > {shownCourses.map((course, i) => ( - + ))} ) : ( diff --git a/site/src/style/theme.scss b/site/src/style/theme.scss index d1ce1ceb..59fc2099 100644 --- a/site/src/style/theme.scss +++ b/site/src/style/theme.scss @@ -114,6 +114,9 @@ } } +.popover { + background-color: var(--overlay1); +} .popover-body { background-color: var(--overlay1); color: var(--text);