Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions website/src/styles/tippy/tippy.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

.tippy-popper[x-placement^='top'] .tippy-arrow {
border-top: 8px solid #333;
border-top: 8px solid var(--gray);
border-top: 8px solid var(--tooltip-bg);
border-right: 8px solid transparent;
border-left: 8px solid transparent;
bottom: -7px;
Expand Down Expand Up @@ -122,7 +122,7 @@

.tippy-popper[x-placement^='bottom'] .tippy-arrow {
border-bottom: 8px solid #333;
border-bottom: 8px solid var(--gray);
border-bottom: 8px solid var(--tooltip-bg);
border-right: 8px solid transparent;
border-left: 8px solid transparent;
top: -7px;
Expand Down Expand Up @@ -209,7 +209,7 @@

.tippy-popper[x-placement^='left'] .tippy-arrow {
border-left: 8px solid #333;
border-left: 8px solid var(--gray);
border-left: 8px solid var(--tooltip-bg);
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
right: -7px;
Expand Down Expand Up @@ -296,7 +296,7 @@

.tippy-popper[x-placement^='right'] .tippy-arrow {
border-right: 8px solid #333;
border-right: 8px solid var(--gray);
border-right: 8px solid var(--tooltip-bg);
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
left: -7px;
Expand Down Expand Up @@ -369,7 +369,7 @@
.tippy-tooltip {
position: relative;
color: #fff;
color: var(--body-bg);
color: var(--tooltip-color);
border-radius: 4px;
font-size: 0.9rem;
padding: 0.3rem 0.6rem;
Expand All @@ -379,7 +379,7 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #333;
background-color: var(--gray);
background-color: var(--tooltip-bg);
}

.tippy-tooltip[data-size='small'] {
Expand Down Expand Up @@ -428,7 +428,7 @@
position: absolute;
will-change: transform;
background-color: #333;
background-color: var(--gray);
background-color: var(--tooltip-bg);
border-radius: 50%;
width: calc(110% + 2rem);
left: 50%;
Expand Down
8 changes: 8 additions & 0 deletions website/src/styles/utils/css-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
// Body font color
--body-color: #{$body-color};

// Tooltips (Tippy)
--tooltip-bg: #{$gray-dark};
--tooltip-color: #fff;

// Shade of grays
--gray: #{$gray};
--gray-mid: #{$gray-mid};
Expand Down Expand Up @@ -57,6 +61,10 @@ body.mode-dark {
// Body font color
--body-color: #aaa;

// Tooltips (Tippy)
--tooltip-bg: #3a3a3a;
--tooltip-color: var(--body-color);

// Shade of grays
--gray: #aaa;
--gray-mid: #7d7d7d;
Expand Down
43 changes: 43 additions & 0 deletions website/src/views/components/module-info/RequisiteRulePopup.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@import '~styles/utils/modules-entry';

.tooltip {
padding: 0.75rem 1rem;
}

.trigger {
display: inline-flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
padding: 0.15rem;
border: 0;
line-height: 0;
color: var(--gray-light);
background: transparent;
cursor: pointer;

&:hover,
&:focus {
outline: none;
color: theme-color();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Focus outline removed without replacement

outline: none on :focus discards the browser's default focus ring for keyboard users. The icon color change alone (from --gray-light to theme-color()) is unlikely to meet WCAG 2.1 SC 2.4.11's visible focus requirement, and many custom themes may have low contrast between these two values. Consider replacing with a visible focus-visible outline (e.g., outline: 2px solid currentColor) instead of suppressing it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: website/src/views/components/module-info/RequisiteRulePopup.scss
Line: 19-23

Comment:
**Focus outline removed without replacement**

`outline: none` on `:focus` discards the browser's default focus ring for keyboard users. The icon color change alone (from `--gray-light` to `theme-color()`) is unlikely to meet WCAG 2.1 SC 2.4.11's visible focus requirement, and many custom themes may have low contrast between these two values. Consider replacing with a visible focus-visible outline (e.g., `outline: 2px solid currentColor`) instead of suppressing it.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3a74cc1 — split hover/focus styles and added a :focus-visible outline (2px solid currentColor with offset) while keeping outline: none only for :focus:not(:focus-visible).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Focus outline removed without replacement

outline: none on :focus suppresses the browser's default focus ring for keyboard users without a visible alternative. The color shift to theme-color() on a small icon button is unlikely to meet WCAG 2.4.7 Focus Visible. Consider using outline: none only on :focus:not(:focus-visible) and keeping the ring for :focus-visible, or adding an explicit box-shadow/outline replacement to keep keyboard navigation accessible.

Prompt To Fix With AI
This is a comment left during a code review.
Path: website/src/views/components/module-info/RequisiteRulePopup.scss
Line: 19-23

Comment:
**Focus outline removed without replacement**

`outline: none` on `:focus` suppresses the browser's default focus ring for keyboard users without a visible alternative. The color shift to `theme-color()` on a small icon button is unlikely to meet WCAG 2.4.7 Focus Visible. Consider using `outline: none` only on `:focus:not(:focus-visible)` and keeping the ring for `:focus-visible`, or adding an explicit `box-shadow`/`outline` replacement to keep keyboard navigation accessible.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same fix as above — addressed in 3a74cc1.


:global(.svg) {
display: block;
width: 1.1rem;
height: 1.1rem;
}
}

.content {
max-width: 28rem;
font-size: $font-size-sm;
text-align: left;
white-space: pre-wrap;
word-break: break-word;
color: var(--tooltip-color);

:global(a) {
color: theme-color();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { screen } from '@testing-library/react';
import { Provider } from 'react-redux';

import { initAction } from 'test-utils/redux';
import reducers from 'reducers';
import configureStore from 'bootstrapping/configure-store';
import renderWithRouterMatch from 'test-utils/renderWithRouterMatch';
import RequisiteRulePopup from './RequisiteRulePopup';

describe(RequisiteRulePopup, () => {
function make(rule: string, summary?: string) {
const initialState = reducers(undefined, initAction());
const { store } = configureStore(initialState);

return renderWithRouterMatch(
<Provider store={store}>
<RequisiteRulePopup rule={rule} summary={summary} />
</Provider>,
{},
);
}

it('renders nothing when rule matches summary', () => {
const rule = 'CS1010 or its equivalent';
const { view } = make(rule, rule);
expect(view.container).toBeEmptyDOMElement();
});

it('renders info icon with accessible label', () => {
make('PROGRAM_TYPES IF_IN Undergraduate Degree THEN (COURSES (1) CS1010:D)', 'CS1010');

expect(
screen.getByRole('button', { name: 'View detailed prerequisite rule' }),
).toBeInTheDocument();
});
});
45 changes: 45 additions & 0 deletions website/src/views/components/module-info/RequisiteRulePopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Info } from 'react-feather';

import LinkModuleCodes from 'views/components/LinkModuleCodes';
import Tooltip from 'views/components/Tooltip';
import styles from './RequisiteRulePopup.scss';

type Props = {
rule: string;
summary?: string;
label?: string;
};

/**
* Info icon that shows the full structured requisite rule in a popup.
*/
export default function RequisiteRulePopup({
rule,
summary,
label = 'View detailed prerequisite rule',
}: Props) {
if (!rule.trim()) return null;
if (summary?.trim() === rule.trim()) return null;

const content = (
<div className={styles.content}>
<LinkModuleCodes>{rule}</LinkModuleCodes>
</div>
);

return (
<Tooltip
content={content}
interactive
arrow
placement="bottom"
maxWidth="none"
touch="hold"
className={styles.tooltip}
>
<button type="button" className={styles.trigger} aria-label={label}>
<Info className="svg svg-small" size={18} strokeWidth={2} />
</button>
</Tooltip>
);
}
16 changes: 16 additions & 0 deletions website/src/views/modules/ModulePageContent.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@ $sticky-top: $navbar-height;
font-size: $font-size-lg;
}

.sectionHeadingRow {
display: flex;
align-items: center;
padding: 0.6rem 0;
margin: 0 0 0.6rem;
border-bottom: 1px solid var(--gray-lighter);
gap: 0.4rem;

.sectionHeading {
flex: 1 1 auto;
padding: 0;
margin: 0;
border-bottom: none;
}
}

.descriptionHeading {
margin-bottom: 0;
font-weight: bold;
Expand Down
8 changes: 7 additions & 1 deletion website/src/views/modules/ModulePageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import LessonTimetable from 'views/components/module-info/LessonTimetable';
import ModuleExamClash from 'views/components/module-info/ModuleExamClash';
import ModuleWorkload from 'views/components/module-info/ModuleWorkload';
import ModuleExamInfo from 'views/components/module-info/ModuleExamInfo';
import RequisiteRulePopup from 'views/components/module-info/RequisiteRulePopup';
import AddModuleDropdown from 'views/components/module-info/AddModuleDropdown';
import SaveModuleButton from 'views/components/module-info/SaveModuleButton';
import Announcements from 'views/components/notfications/Announcements';
Expand Down Expand Up @@ -266,7 +267,12 @@ const ModulePageContent: React.FC<Props> = ({ module, archiveYear }) => {
</div>

<section className={styles.section} id={SIDE_MENU_ITEMS.prerequisites}>
<h2 className={styles.sectionHeading}>Prerequisite Tree</h2>
<div className={styles.sectionHeadingRow}>
<h2 className={styles.sectionHeading}>Prerequisite Tree</h2>
{module.prerequisiteRule && (
<RequisiteRulePopup rule={module.prerequisiteRule} summary={module.prerequisite} />
)}
</div>
<ErrorBoundary>
<ModuleTree
moduleCode={moduleCode}
Expand Down
4 changes: 2 additions & 2 deletions website/src/views/modules/ModuleTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ export const ModuleTreeComponent: React.FC<Props> = (props) => {

<p className="alert alert-warning">
This new version of the prerequisite tree is being tested and may not be accurate. Viewers
are encouraged to double check details with the prerequisite text above. To report bugs with
the new tree, please post a bug report on GitHub (preferred) at{' '}
are encouraged to double check details with the prerequisite information above. To report
bugs with the new tree, please post a bug report on GitHub (preferred) at{' '}
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
target="_blank"
Expand Down
10 changes: 5 additions & 5 deletions website/src/views/modules/__snapshots__/ModuleTree.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ exports[`ModuleTreeComponent > should grey out modules that are not in module ba
<p
class="alert alert-warning"
>
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite text above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite information above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
rel="noopener noreferrer nofollow"
Expand Down Expand Up @@ -541,7 +541,7 @@ exports[`ModuleTreeComponent > should render prereq branch with nOf condition >
<p
class="alert alert-warning"
>
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite text above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite information above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
rel="noopener noreferrer nofollow"
Expand Down Expand Up @@ -953,7 +953,7 @@ exports[`ModuleTreeComponent > should render prereq tree of module > CS3244 1`]
<p
class="alert alert-warning"
>
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite text above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite information above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
rel="noopener noreferrer nofollow"
Expand Down Expand Up @@ -1045,7 +1045,7 @@ exports[`ModuleTreeComponent > should render prereq tree to the right when tree
<p
class="alert alert-warning"
>
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite text above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite information above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
rel="noopener noreferrer nofollow"
Expand Down Expand Up @@ -1313,7 +1313,7 @@ exports[`ModuleTreeComponent > should render requirements fulfilled tree of modu
<p
class="alert alert-warning"
>
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite text above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
This new version of the prerequisite tree is being tested and may not be accurate. Viewers are encouraged to double check details with the prerequisite information above. To report bugs with the new tree, please post a bug report on GitHub (preferred) at
<a
href="https://github.com/nusmodifications/nusmods/issues/new/choose"
rel="noopener noreferrer nofollow"
Expand Down