Skip to content

Commit c9f9663

Browse files
committed
Merge branch 'redesign-2024' into redesign/general-improvements-8
2 parents 2c3eeaa + 0580688 commit c9f9663

24 files changed

+136
-731
lines changed

.github/workflows/cypress.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
find ./src/test/pages/__image_snapshots__ -type f -name "*.actual.png" -exec bash -c 'exiftool -overwrite_original -FRSOURCE_CPVRD_V="1" "$1"; mv "$1" "${1/.actual./.}"' shell {} \;
5050
git fetch origin $target_ref
5151
git checkout -B $update_branch_name origin/$target_ref
52-
git commit -am "Update VRT baselines"
52+
git add . && git commit -m "Update VRT baselines"
5353
git push --set-upstream origin $update_branch_name --force
5454
echo "TARGET_REF=$target_ref" >> "$GITHUB_ENV"
5555
echo "UPDATE_BRANCH_NAME=$update_branch_name" >> "$GITHUB_ENV"

cypress.config.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,31 @@ const SITE_STRING = process.env.CYPRESS_SITE == 'ada' ? 'ada' : 'phy';
55
const UPDATE_BASELINE = process.env.CYPRESS_UPDATE_BASELINE == 'true';
66

77
export default defineConfig({
8-
component: {
9-
devServer: {
10-
framework: "react",
11-
bundler: "webpack",
12-
webpackConfig: require(`./config/webpack.config.${SITE_STRING}.cypress.js`)
13-
},
14-
indexHtmlFile: `cypress/support/component-index-${SITE_STRING}.html`,
15-
supportFile: `cypress/support/component-${SITE_STRING}.tsx`,
16-
setupNodeEvents(on, config) {
17-
initPlugin(on, config);
18-
on('before:browser:launch', (browser, launchOptions) => {
19-
if (browser.family === 'chromium') {
20-
// Disable smooth scrolling, which can interfere with screenshots
21-
launchOptions.args.push('--force-color-profile=srgb');
22-
launchOptions.args.push('--disable-low-res-tiling');
23-
launchOptions.args.push('--disable-smooth-scrolling');
8+
component: {
9+
devServer: {
10+
framework: "react",
11+
bundler: "webpack",
12+
webpackConfig: require(`./config/webpack.config.${SITE_STRING}.cypress.js`)
13+
},
14+
indexHtmlFile: `cypress/support/component-index-${SITE_STRING}.html`,
15+
supportFile: `cypress/support/component-${SITE_STRING}.tsx`,
16+
setupNodeEvents(on, config) {
17+
initPlugin(on, config);
18+
on('before:browser:launch', (browser, launchOptions) => {
19+
if (browser.family === 'chromium') {
20+
// Disable smooth scrolling, which can interfere with screenshots
21+
launchOptions.args.push('--force-color-profile=srgb');
22+
launchOptions.args.push('--disable-low-res-tiling');
23+
launchOptions.args.push('--disable-smooth-scrolling');
24+
}
25+
return launchOptions;
26+
});
2427
}
25-
return launchOptions;
26-
});
28+
},
29+
env: {
30+
pluginVisualRegressionImagesPath : `{spec_path}/__image_snapshots__/${SITE_STRING}`,
31+
pluginVisualRegressionMaxDiffThreshold: 0,
32+
pluginVisualRegressionUpdateImages: UPDATE_BASELINE,
33+
pluginVisualRegressionCreateMissingImages: false,
2734
}
28-
},
29-
env: {
30-
pluginVisualRegressionImagesPath : `{spec_path}/__image_snapshots__/${SITE_STRING}`,
31-
pluginVisualRegressionMaxDiffThreshold: 0,
32-
pluginVisualRegressionUpdateImages: UPDATE_BASELINE,
33-
}
3435
});

docker-entrypoint-vrt.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/bash
22

33
yarn install --frozen-lockfile
4-
yarn cypress run --component --browser chrome
4+
yarn cypress run --component --browser chrome "$@"

public/assets/common/logos/university_of_cambridge.svg

Lines changed: 1 addition & 634 deletions
Loading

public/assets/common/logos/university_of_cambridge_white.svg

Lines changed: 1 addition & 0 deletions
Loading

src/app/components/content/IsaacCodeSnippet.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ const IsaacCodeSnippet = ({doc}: IsaacCodeProps) => {
5656
</div>
5757
{doc.url && <Row>
5858
<Col className="text-center mb-2">
59-
<a href={doc.url} onClick={logViewOnGitHub} target="_blank" rel="noopener noreferrer">View on GitHub</a>
59+
<a className="no-print" href={doc.url} onClick={logViewOnGitHub} target="_blank" rel="noopener noreferrer">View on GitHub</a>
60+
<a className="only-print" href={doc.url} target="_blank" rel="noopener noreferrer">{doc.url}</a>
6061
</Col>
6162
</Row>}
6263
</>;

src/app/components/content/IsaacContent.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {IsaacFigure} from "./IsaacFigure";
88
import {IsaacGlossaryTerm} from "./IsaacGlossaryTerm";
99
import {ContentDTO} from "../../../IsaacApiTypes";
1010
import {IsaacQuickQuestion} from "./IsaacQuickQuestion";
11-
import {IsaacTabs} from "./IsaacTabs";
11+
import {IsaacTabs, isTabs} from "./IsaacTabs";
1212
import {IsaacAccordion} from "./IsaacAccordion";
1313
import {IsaacHorizontal} from "./IsaacHorizontal";
1414
import {RouteComponentProps, withRouter} from "react-router-dom";
@@ -75,6 +75,7 @@ export const IsaacContent = withRouter((props: IsaacContentProps) => {
7575
default:
7676
switch (layout) {
7777
case "tabs": selectedComponent = <IsaacTabs {...props} />; break;
78+
case isTabs(layout): selectedComponent = <IsaacTabs {...props} style={layout?.split('/')[1]} />; break;
7879
case "callout": selectedComponent = <IsaacCallout {...props} />; break;
7980
case "accordion": selectedComponent = <IsaacAccordion {...props} />; break;
8081
case "horizontal": selectedComponent = <IsaacHorizontal {...props} />; break;

src/app/components/content/IsaacHints.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,16 @@ export const IsaacTabbedHints = ({hints, questionPartId}: HintsProps) => {
7979
}, [hints]);
8080

8181
return <div className="tabbed-hints">
82-
{hints && <Tabs onActiveTabChange={logHintView} className="no-print" style="dropdowns" tabTitleClass="hint-tab-title" tabContentClass="mt-1" deselectable activeTabOverride={-1}>
83-
{Object.assign({}, ...hints.map((hint, index) => ({
84-
[titles[index]]: <div className="mt-3 mt-lg-4 pt-2">
85-
<IsaacContent doc={hint} />
86-
</div>
87-
})))}
88-
</Tabs>}
82+
{hints && !!hints.length && <>
83+
<h5 className="text-theme mb-2">Need some help?</h5>
84+
<Tabs onActiveTabChange={logHintView} className="no-print" style="dropdowns" tabTitleClass="hint-tab-title" tabContentClass="mt-1" deselectable activeTabOverride={-1}>
85+
{Object.assign({}, ...hints.map((hint, index) => ({
86+
[titles[index]]: <div className="mt-3 mt-lg-4 pt-2">
87+
<IsaacContent doc={hint} />
88+
</div>
89+
})))}
90+
</Tabs>
91+
</>}
8992
<PrintOnlyHints hints={hints} />
9093
</div>;
9194
};

src/app/components/content/IsaacTabs.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {ReactElement, useEffect, useState} from "react";
2-
import {Tabs} from "../elements/Tabs";
2+
import {Tabs, TabStyle} from "../elements/Tabs";
33
import {ContentDTO} from "../../../IsaacApiTypes";
44
import {IsaacContent} from "./IsaacContent";
55
import {isAda, isDefined} from "../../services";
@@ -10,12 +10,17 @@ interface IsaacTabsProps {
1010
children: {title?: string; children?: ContentDTO[]}[],
1111
expandable?: boolean
1212
};
13+
style?: TabStyle;
1314
}
1415

1516
type IsaacTabChildren = {[title: string]: ReactElement};
1617

18+
export const isTabs = (layout?: string) => {
19+
return layout && layout.startsWith("tabs/") ? layout : false;
20+
};
21+
1722
export const IsaacTabs = (props: any) => {
18-
const { doc: { children: tabs, expandable} } = props as IsaacTabsProps;
23+
const { doc: { children: tabs, expandable}, style } = props as IsaacTabsProps;
1924
const [ tabTitlesToContent , setTabTitlesToContent ] = useState<IsaacTabChildren>({});
2025

2126
useEffect(() => {
@@ -30,7 +35,7 @@ export const IsaacTabs = (props: any) => {
3035
}, [tabs]);
3136

3237
const adaCardClasses = "card card-body border bg-white pb-2 mb-4";
33-
return <Tabs className={classNames("isaac-tab", {[adaCardClasses]: isAda})} tabContentClass="pt-4" expandable={expandable}>
38+
return <Tabs className={classNames("isaac-tab", {[adaCardClasses]: isAda})} tabContentClass={style === "dropdowns" ? "pt-2" : "pt-4"} expandable={expandable} style={style}>
3439
{tabTitlesToContent}
3540
</Tabs>;
3641
};

src/app/components/elements/Tabs.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Markup} from "./markup";
1010
import { AffixButton } from "./AffixButton";
1111

1212
type StringOrTabFunction = string | ((tabTitle: string, tabIndex: number) => string);
13-
13+
export type TabStyle = "tabs" | "buttons" | "dropdowns";
1414
interface TabsProps {
1515
className?: string;
1616
tabTitleClass?: StringOrTabFunction;
@@ -22,7 +22,7 @@ interface TabsProps {
2222
refreshHash?: string;
2323
expandable?: boolean;
2424
singleLine?: boolean;
25-
style?: "tabs" | "buttons" | "dropdowns";
25+
style?: TabStyle;
2626
}
2727

2828
function callOrString(stringOrTabFunction: StringOrTabFunction | undefined, tabTitle: string, tabIndex: number) {
@@ -32,8 +32,8 @@ function callOrString(stringOrTabFunction: StringOrTabFunction | undefined, tabT
3232
}
3333

3434
// e.g.: Tab 1 | Tab 2 | Tab 3
35-
const TabNavbar = ({singleLine, children, tabTitleClass, activeTab, changeTab}: TabsProps & {activeTab: number; changeTab: (i: number) => void}) => {
36-
return <Nav tabs className={classNames("flex-wrap", {"guaranteed-single-line": singleLine})}>
35+
const TabNavbar = ({singleLine, children, tabTitleClass, activeTab, changeTab, className}: TabsProps & {activeTab: number; changeTab: (i: number) => void;}) => {
36+
return <Nav tabs className={classNames(className, "flex-wrap", {"guaranteed-single-line": singleLine})}>
3737
{Object.keys(children).map((tabTitle, mapIndex) => {
3838
const tabIndex = mapIndex + 1;
3939
const linkClasses = callOrString(tabTitleClass, tabTitle, tabIndex);
@@ -84,22 +84,16 @@ const ButtonNavbar = ({children, activeTab, changeTab, tabTitleClass=""}: TabsPr
8484
};
8585

8686
const DropdownNavbar = ({children, activeTab, changeTab, tabTitleClass=""}: TabsProps & {activeTab: number; changeTab: (i: number) => void}) => {
87-
return <div className="my-3">
88-
{!!Object.keys(children).length && <h5 className="text-theme mb-2">Need some help?</h5>}
89-
<div>
90-
{Object.keys(children).map((tabTitle, i) =>
91-
<AffixButton key={tabTitle} color="tint" className={classNames("btn-dropdown me-2 mb-2", tabTitleClass, {"active": activeTab === i + 1})} onClick={() => changeTab(i + 1)} affix={{
92-
affix: "icon-chevron-down",
93-
position: "suffix",
94-
type: "icon",
95-
}}>
96-
{tabTitle}
97-
</AffixButton>
98-
)}
99-
</div>
100-
{activeTab > 0 && <div className="mt-3">
101-
{children[activeTab]}
102-
</div>}
87+
return <div className="mt-3 mb-1">
88+
{Object.keys(children).map((tabTitle, i) =>
89+
<AffixButton key={tabTitle} color="tint" className={classNames("btn-dropdown me-2 mb-2", tabTitleClass, {"active": activeTab === i + 1})} onClick={() => changeTab(i + 1)} affix={{
90+
affix: "icon-chevron-down",
91+
position: "suffix",
92+
type: "icon",
93+
}}>
94+
{tabTitle}
95+
</AffixButton>
96+
)}
10397
</div>;
10498
};
10599

@@ -133,9 +127,9 @@ export const Tabs = (props: TabsProps) => {
133127

134128
return <div className={classNames({"mt-4": isDefined(expandButton)}, outerClasses)} ref={updateExpandRef}>
135129
{expandButton}
136-
<div className={classNames(className, innerClasses, "position-relative")}>
130+
<div className={classNames(className, innerClasses, `tab-style-${style}`, "position-relative")}>
137131
{style === "tabs"
138-
? <TabNavbar activeTab={activeTab} changeTab={changeTab} {...props}>{children}</TabNavbar>
132+
? <TabNavbar {...props} className="no-print" activeTab={activeTab} changeTab={changeTab}>{children}</TabNavbar>
139133
: style === "buttons"
140134
? <ButtonNavbar activeTab={activeTab} changeTab={changeTab} {...props}>{children}</ButtonNavbar>
141135
: <DropdownNavbar activeTab={activeTab} changeTab={changeTab} {...props}>{children}</DropdownNavbar>
@@ -144,9 +138,13 @@ export const Tabs = (props: TabsProps) => {
144138
<TabContent activeTab={activeTab} className={tabContentClass}>
145139
{Object.entries(children).map(([tabTitle, tabBody], mapIndex) => {
146140
const tabIndex = mapIndex + 1;
147-
return <TabPane key={tabTitle} tabId={tabIndex}>
148-
{tabBody as ReactNode}
149-
</TabPane>;
141+
return <>
142+
{/* This navbar exists only when printing so each tab has its own heading */}
143+
{style === "tabs" && <TabNavbar {...props} className={classNames("d-none d-print-flex mb-3 mt-2", {"mt-n4": mapIndex === 0 && tabContentClass.includes("pt-4")})} activeTab={tabIndex} changeTab={changeTab}>{children}</TabNavbar>}
144+
<TabPane key={tabTitle} tabId={tabIndex}>
145+
{tabBody as ReactNode}
146+
</TabPane>
147+
</>;
150148
})}
151149
</TabContent>
152150
</ExpandableParentContext.Provider>

src/app/components/site/phy/FooterPhy.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const FooterPhy = () => (
1010
<Row className="pt-5">
1111
<Col xl={{size: 3, offset: 0}}>
1212
<a href="https://www.cam.ac.uk/" target="_blank" rel="noopener" className="mt-2 mb-1">
13-
<img src="/assets/common/logos/university_of_cambridge.svg" alt='University of Cambridge website' width="160px" className='footer-org-logo' />
13+
<img src="/assets/common/logos/university_of_cambridge.svg" alt='University of Cambridge website' className='footer-org-logo' />
1414
</a>
1515
<div className="logo-text">
1616
Funded by {' '} <ExternalLink href="https://www.cam.ac.uk/" className="d-inline">
@@ -19,7 +19,7 @@ export const FooterPhy = () => (
1919
<br />
2020
Supported by {' '} <ExternalLink href="https://www.gov.uk/government/organisations/department-for-education" className="d-inline">
2121
<u>Department for Education</u>
22-
</ExternalLink> and {' '}
22+
</ExternalLink> and {' '}
2323
<ExternalLink href="https://www.ogdentrust.com/" className="d-inline">
2424
<u>The&nbsp;Ogden&nbsp;Trust</u>
2525
</ExternalLink>.
@@ -44,7 +44,7 @@ export const FooterPhy = () => (
4444
<Link to="/privacy">Privacy policy</Link>
4545
<Link to="/cookies">Cookie policy</Link>
4646
<Link to="/terms">Terms of use</Link>
47-
</Col>
48-
</Row>
47+
</Col>
48+
</Row>
4949
</footer>
5050
);

src/app/components/site/phy/HomepagePhy.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const HomepageHero = () => {
6969
isStudent={false}/>
7070
</Col>
7171
</Row>
72-
</Container>
72+
</Container>
7373
</div>;
7474
}
7575
};
@@ -123,7 +123,7 @@ export const HomepagePhy = () => {
123123
useEffect( () => {document.title = SITE_TITLE;}, []);
124124

125125
const user = useAppSelector(selectors.user.orNull);
126-
126+
127127
const {data: news} = useGetNewsPodListQuery({subject: "physics"});
128128

129129
const [dashboardView, setDashboardView] = useState<"student" | "teacher" | undefined>(undefined);
@@ -163,16 +163,16 @@ export const HomepagePhy = () => {
163163
useEffect(() => {
164164
getEventsList({startIndex: 0, limit: 2, typeFilter: EventTypeFilter["All groups"], statusFilter: EventStatusFilter["Upcoming events"], stageFilter: [STAGE.ALL]});
165165
}, []);
166-
166+
167167
return <>
168168
<div id="homepage" className="homepage pb-5">
169169
<section id="dashboard">
170170
{isLoggedIn(user) && (isTutorOrAbove(user)
171171
? <TeacherDashboard assignmentsSetByMe={assignmentsSetByMe} quizzesSetByMe={isTutor(user) ? [] : quizzesSetByMe} groups={groups} myAssignments={myAssignments}
172-
myQuizAssignments={myQuizAssignments} streakRecord={streakRecord} dashboardView={dashboardView} setDashboardView={setDashboardView} />
172+
myQuizAssignments={myQuizAssignments} streakRecord={streakRecord} dashboardView={dashboardView} setDashboardView={setDashboardView} />
173173
: <StudentDashboard assignments={myAssignments} quizAssignments={myQuizAssignments} streakRecord={streakRecord} groups={groups} />)}
174174
</section>
175-
<section id="homepage-hero">
175+
<section id="homepage-hero">
176176
{!isLoggedIn(user) && <HomepageHero />}
177177
</section>
178178
<Container>
@@ -182,15 +182,15 @@ export const HomepagePhy = () => {
182182
<h3>Explore and learn!</h3>
183183
<div className="section-divider ms-2"/>
184184
</div>
185-
<ListViewCards cards={cards}/>
186-
</div>
185+
<ListViewCards cards={cards}/>
186+
</div>
187187
</section>
188188
<section id="events-news">
189189
<Row className="mt-5 row-cols-1 row-cols-lg-2">
190190
<div className="d-flex flex-column mt-3">
191191
<div className="d-flex">
192-
<h3>Upcoming Events</h3>
193-
<Link to="/events" className="news-events-link">More events</Link>
192+
<h3>Upcoming events</h3>
193+
<Link to="/events" className="news-events-link">More events</Link>
194194
<div className="section-divider-bold"/>
195195
</div>
196196
<ShowLoadingQuery
@@ -204,10 +204,10 @@ export const HomepagePhy = () => {
204204
</Row>;
205205
}}/>
206206
</div>
207-
<div className="d-flex flex-column mt-3">
207+
<div className="d-flex flex-column mt-3">
208208
<div className="d-flex">
209-
<h3>News & Features</h3>
210-
<Link to="/news" className="news-events-link">More news</Link>
209+
<h3>News and features</h3>
210+
<Link to="/news" className="news-events-link">More news</Link>
211211
<div className="section-divider-bold"/>
212212
</div>
213213
{news && <Row className="h-100">

src/app/components/site/phy/RoutesPhy.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import { Chemistry16 } from "../../pages/books_old/chemistry_16";
4444
import { LinkingConcepts } from "../../pages/books_old/linking_concepts";
4545
import { PhysBookYrNine } from "../../pages/books_old/phys_book_yr9";
4646
import { PreUniMaths } from "../../pages/books_old/pre_uni_maths";
47-
import { PreUniMaths2e } from "../../pages/books_old/pre_uni_maths_2e";
4847
import { StepUpPhys } from "../../pages/books_old/step_up_phys";
4948
import { QuizView } from "../../pages/quizzes/QuizView";
5049

@@ -67,7 +66,6 @@ const subjectStagePairPages : Record<string, React.ComponentType<RouteComponentP
6766
// TODO: remove these (and related imports) when we have replaced old book index pages with API-based ones
6867
const old_books : Record<string, React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any> | undefined> = {
6968
"/books/pre_uni_maths": PreUniMaths,
70-
"/books/pre_uni_maths_2e": PreUniMaths2e,
7169
"/books/chemistry_16": Chemistry16,
7270
"/books/quantum_mechanics_primer": QuantumMechanicsPrimer,
7371
"/books/solve_physics_problems": SolvingPhysProblems,

src/scss/common/tabs.scss

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
// ISAAC
22
.isaac-tab {
33
border: solid 1px $gray-103;
4-
box-shadow: 0 2px 30px 0 $shadow-08;
5-
padding: 1.5rem 1.5rem 0.5rem;
4+
padding: 1.5rem;
65
margin-top: 1.5rem;
7-
margin-bottom: 3rem;
8-
overflow: auto;
9-
background-color: #fff !important;
6+
margin-bottom: 2rem;
7+
8+
&:not(.tab-style-dropdowns) {
9+
background-color: #fff;
10+
box-shadow: 0 2px 30px 0 $shadow-08;
11+
overflow: auto; // unsure what this was for originally, on dropdowns it cuts off the first button's box shadow
12+
}
13+
&.tab-style-dropdowns {
14+
padding: 0 0 1.5rem;
15+
margin-top: 0;
16+
.tab-content .tab-pane {
17+
background-color: #fff;
18+
padding: 0.5rem;
19+
20+
.content-video-container {
21+
margin-bottom: 0;
22+
}
23+
}
24+
}
1025
}
1126

1227

0 commit comments

Comments
 (0)