-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merge course popovers #551
base: main
Are you sure you want to change the base?
Changes from 14 commits
129bbbe
82498db
a2dd379
9cbaa93
a5b451e
e194666
ae136a1
101a0ce
07aeee9
c323679
de9fa61
e0e2c05
025aa9e
98bb1dd
77a1e70
92d84bb
4ec9a23
ffb01fa
4584700
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CoursePopoverProps> = (props) => { | ||
const { | ||
department, | ||
courseNumber, | ||
title, | ||
minUnits, | ||
maxUnits, | ||
description, | ||
prerequisiteText, | ||
corequisites, | ||
requiredCourses, | ||
} = props; | ||
|
||
return ( | ||
<Popover.Content className="course-popover"> | ||
<div className="popover-name"> | ||
{department + ' ' + courseNumber + ' '} | ||
<span className="popover-units">({minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`} units)</span> | ||
</div> | ||
<div className="popover-description"> | ||
<span className="popover-subtitle">{title + ':'}</span> | ||
<br /> | ||
{description} | ||
</div> | ||
{prerequisiteText && ( | ||
<div className="popover-detail"> | ||
<span className="popover-detail-prefix">Prerequisites:</span> {prerequisiteText} | ||
</div> | ||
)} | ||
{corequisites && ( | ||
<div className="popover-detail"> | ||
<span className="popover-detail-prefix">Corequisites:</span> {corequisites} | ||
</div> | ||
)} | ||
{requiredCourses && ( | ||
<div className="popover-detail"> | ||
<div className="popover-detail-warning"> | ||
<ExclamationTriangle className="popover-detail-warning-icon" /> | ||
Prerequisite{requiredCourses?.length > 1 ? 's' : ''} Not Met: {requiredCourses?.join(', ')} | ||
</div> | ||
<div className="popover-detail-italics"> | ||
Already completed? Click "Transfer Credits" at the top of the roadmap viewer to add{' '} | ||
{requiredCourses?.length > 1 ? 'these prerequisites' : 'this prerequisite'}. | ||
</div> | ||
</div> | ||
)} | ||
</Popover.Content> | ||
); | ||
}; | ||
|
||
export default CoursePopover; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'; | ||
|
@@ -16,6 +18,7 @@ interface CourseProps extends CourseGQLData { | |
onAddToBag?: () => void; | ||
isInBag?: boolean; | ||
removeFromBag?: () => void; | ||
openPopoverLeft?: boolean; | ||
} | ||
|
||
const Course: FC<CourseProps> = (props) => { | ||
|
@@ -35,46 +38,11 @@ const Course: FC<CourseProps> = (props) => { | |
onAddToBag, | ||
isInBag, | ||
removeFromBag, | ||
openPopoverLeft, | ||
} = props; | ||
const CoursePopover = ( | ||
<Popover id={'course-popover-' + id}> | ||
<Popover.Content> | ||
<div className="course-popover"> | ||
<div className="popover-name"> | ||
{department + ' ' + courseNumber} {title} | ||
</div> | ||
<div className="popover-units"> | ||
<span className="popover-units-value">{minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`}</span>{' '} | ||
units | ||
</div> | ||
<div className="popover-description">{description}</div> | ||
{prerequisiteText && ( | ||
<div className="popover-detail"> | ||
<span className="popover-detail-prefix">Prerequisites:</span> {prerequisiteText} | ||
</div> | ||
)} | ||
{corequisites && ( | ||
<div className="popover-detail"> | ||
<span className="popover-detail-prefix">Corequisites:</span> {corequisites} | ||
</div> | ||
)} | ||
</div> | ||
</Popover.Content> | ||
</Popover> | ||
); | ||
|
||
const WarningPopover = ( | ||
<Popover id={'warning-popover-' + id}> | ||
<Popover.Content> | ||
Prerequisite(s) not met! Missing: {requiredCourses?.join(', ')} | ||
<br /> | ||
Already completed prerequisite(s) at another institution? Click 'Transfer Credits' at the top of the planner to | ||
clear the prerequisite(s). | ||
</Popover.Content> | ||
</Popover> | ||
); | ||
|
||
const courseRoute = '/course/' + props.department.replace(/\s+/g, '') + props.courseNumber.replace(/\s+/g, ''); | ||
const isMobile = useIsMobile(); | ||
|
||
return ( | ||
<div className={`course ${requiredCourses ? 'invalid' : ''}`}> | ||
|
@@ -86,14 +54,26 @@ const Course: FC<CourseProps> = (props) => { | |
</a> | ||
<span className="units">, {minUnits === maxUnits ? minUnits : `${minUnits}-${maxUnits}`} units</span> | ||
</span> | ||
<OverlayTrigger trigger={['hover', 'focus']} placement="auto" overlay={CoursePopover} delay={100}> | ||
<InfoCircle /> | ||
<OverlayTrigger | ||
trigger={['hover', 'focus']} | ||
placement={isMobile ? 'bottom' : openPopoverLeft ? 'left-start' : 'right-start'} | ||
overlay=<Popover className="ppc-popover" id={'course-popover-' + id}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When extracting There is little documentation on how the OverlayTrigger works with what's passed into I didn't want to overcomplicate things, so this led to putting the top-level There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. to be honest, I think we might just want to create our own custom popover component, especially if we're going to need to be able to click on things inside the popover (bookmark button) without it closing on its own |
||
<CoursePopover | ||
department={department} | ||
courseNumber={courseNumber} | ||
title={title} | ||
minUnits={minUnits} | ||
maxUnits={maxUnits} | ||
description={description} | ||
prerequisiteText={prerequisiteText} | ||
corequisites={corequisites} | ||
requiredCourses={requiredCourses} | ||
/> | ||
</Popover> | ||
delay={100} | ||
> | ||
{requiredCourses ? <ExclamationTriangle /> : <InfoCircle />} | ||
</OverlayTrigger> | ||
{requiredCourses && ( | ||
<OverlayTrigger trigger={['hover', 'focus']} placement="right" overlay={WarningPopover} delay={100}> | ||
<ExclamationTriangle /> | ||
</OverlayTrigger> | ||
)} | ||
</div> | ||
{onDelete ? ( | ||
<ThemeContext.Consumer> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on research into the Boostrap
Popover
, it seems this is needed, but using!important
is typically not good practiceTried using
margin-top
, differentposition
s,transform: translate
(these do nothing)Tried:
(this does nothing)
Tried:
This results in partial success, but does not render the shadow or border correctly on the top portion (especially visible in light mode)--the shadow is vertically too short, so it would take multiple overlapping and offset shadows to cover that portion
Suggestions would be appreciated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah it looks like it was styled on the element itself, so
!important
is the only way to override that