Skip to content

Commit

Permalink
Merge branch 'main' into issues/775-Enable_the_project_bar_in_the_web…
Browse files Browse the repository at this point in the history
…_component
  • Loading branch information
sra405 authored Dec 4, 2023
2 parents b149dc4 + 165d3c5 commit c695239
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 34 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Added

- ProjectBar functionality in the web component (#799)
- Quiz rendering in InstructionsPanel (#777)
- Styling for the task section of the instructions (#781)
- Styling for the instructions callouts (#788)
- Output styles for Instructions (#790)
- Styling for the instructions code snippets (#795)

### Changed

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ This class renders a bordered `div` with monospaced text that resembles Python o
<div class="c-project-output">{output content}</div>
```

#### Code snippets

Python code snippets are styled and syntax-highlighted using the `language-python` class:

```html
<code class="language-python">print('hello world')</code>
```

## Deployment

Deployment is managed through Github actions. The UI is deployed to staging and production environments via an S3 bucket. This requires the following environment variables to be set
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@codemirror/lang-css": "^6.0.0",
"@codemirror/lang-html": "^6.1.2",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/lang-python": "^6.0.2",
"@codemirror/lang-python": "6.1.2",
"@codemirror/language": "^6.2.1",
"@codemirror/view": "^6.3.0",
"@hello-pangea/dnd": "^16.2.0",
Expand Down Expand Up @@ -48,6 +48,7 @@
"node-html-parser": "^6.1.5",
"oidc-client": "^1.11.5",
"parse-link-header": "^2.0.0",
"prismjs": "^1.29.0",
"prompts": "2.4.0",
"prop-types": "^15.8.1",
"rc-resize-observer": "^1.3.1",
Expand Down
26 changes: 26 additions & 0 deletions src/assets/stylesheets/Instructions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@
@include font-size-1-25(bold);
margin: 0;
}

code {
color: $rpf-white;
background-color: $rpf-grey-700;
border-radius: 8px;
padding: calc(0.75 * $space-0-125) $space-0-5;
}

.language-python {
.number, .boolean, .function {
color: $rpf-syntax-blue;
}
.keyword {
color: $rpf-syntax-pink;
}
.string, .char {
color: $rpf-syntax-green;
}
.comment {
color: $rpf-syntax-grey;
}

.keyword-print {
color: $rpf-white;
}
}

.c-project-heading--task {
@extend .rpf-squiggle-heading;
Expand Down
6 changes: 6 additions & 0 deletions src/assets/stylesheets/rpf_design_system/colours.scss
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,9 @@ $rpf-grey-600: #4a4d59;

$rpf-text-secondary: #4d575b;
$rpf-text-secondary-dark: #cccccc;

// Syntax highlighting
$rpf-syntax-blue: #1498D0;
$rpf-syntax-green: #6CE68D;
$rpf-syntax-grey: #C1C1C1;
$rpf-syntax-pink: #FF00A4;
1 change: 1 addition & 0 deletions src/assets/themes/editorDarkTheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const editorDarkTheme = EditorView.theme(
".ͼc": { color: "#1498D0" },
".ͼd": { color: "#1498D0" },
".ͼe": { color: "#6CE68D" },
".ͼf": { color: "#6CE68D" },
".ͼg": { color: "#1498D0" },
".ͼj": { color: "#1498D0" },
".ͼm": { color: "#C1C1C1" },
Expand Down
1 change: 1 addition & 0 deletions src/assets/themes/editorLightTheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const editorLightTheme = EditorView.theme(
"border-inline-start": "solid grey",
},
},
".ͼf": { color: "#AA1111" },
},
{ dark: false },
);
Original file line number Diff line number Diff line change
@@ -1,28 +1,51 @@
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useMemo } from "react";
import SidebarPanel from "../SidebarPanel";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import ProgressBar from "./ProgressBar/ProgressBar";
import "../../../../assets/stylesheets/Instructions.scss";
import "prismjs/plugins/highlight-keywords/prism-highlight-keywords.js";

const InstructionsPanel = () => {
const steps = useSelector((state) => state.instructions.project.steps);
const steps = useSelector((state) => state.instructions.project?.steps);
const quiz = useSelector((state) => state.instructions?.quiz);

const currentStepPosition = useSelector(
(state) => state.instructions.currentStepPosition,
);
const { t } = useTranslation();
const stepContent = useRef();

const isQuiz = useMemo(() => {
return !!quiz?.questionCount;
}, [quiz]);

const applySyntaxHighlighting = (container) => {
const codeElements = container.querySelectorAll(".language-python");

codeElements.forEach((element) => {
window.Prism.highlightElement(element);
});
};

useEffect(() => {
if (steps[currentStepPosition]) {
const setStepContent = (content) => {
stepContent.current.parentElement.scrollTo({ top: 0 });
stepContent.current.innerHTML = steps[currentStepPosition].content;
stepContent.current.innerHTML = content;
applySyntaxHighlighting(stepContent.current);
};

if (isQuiz) {
setStepContent(quiz.questions[quiz.currentQuestion]);
} else if (steps[currentStepPosition]) {
setStepContent(steps[currentStepPosition].content);
}
}, [steps, currentStepPosition]);
}, [steps, currentStepPosition, quiz, isQuiz]);

return (
<SidebarPanel
heading={t("instructionsPanel.projectSteps")}
Footer={ProgressBar}
Footer={!isQuiz && ProgressBar}
>
<div className="project-instructions" ref={stepContent}></div>
</SidebarPanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,98 @@ import { Provider } from "react-redux";
import configureStore from "redux-mock-store";

window.HTMLElement.prototype.scrollTo = jest.fn();
window.Prism = {
highlightElement: jest.fn(),
};

beforeEach(() => {
const mockStore = configureStore([]);
const initialState = {
instructions: {
project: {
steps: [{ content: "<p>step 0</p>" }, { content: "<p>step 1</p>" }],
describe("It renders project steps when there is no quiz", () => {
beforeEach(() => {
const mockStore = configureStore([]);
const initialState = {
instructions: {
project: {
steps: [
{ content: "<p>step 0</p>" },
{
content:
"<p>step 1</p><code class='language-python'>print('hello')</code>",
},
],
},
quiz: {},
currentStepPosition: 1,
},
currentStepPosition: 1,
},
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<InstructionsPanel />
</Provider>,
);
});
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<InstructionsPanel />
</Provider>,
);
});

test("Renders with correct instruction step content", () => {
expect(screen.queryByText("step 1")).toBeInTheDocument();
test("Renders with correct instruction step content", () => {
expect(screen.queryByText("step 1")).toBeInTheDocument();
});

test("Scrolls instructions to the top", () => {
expect(window.HTMLElement.prototype.scrollTo).toHaveBeenCalledWith({
top: 0,
});
});

test("Renders the progress bar", () => {
expect(screen.queryByRole("progressbar")).toBeInTheDocument();
});

test("Applies syntax highlighting", () => {
const codeElement = document.getElementsByClassName("language-python")[0];
expect(window.Prism.highlightElement).toHaveBeenCalledWith(codeElement);
});
});

test("Scrolls instructions to the top", () => {
expect(window.HTMLElement.prototype.scrollTo).toHaveBeenCalledWith({
top: 0,
describe("It renders a quiz when it has one", () => {
beforeEach(() => {
const mockStore = configureStore([]);
const initialState = {
instructions: {
project: {
steps: [{ content: "<p>step 0</p>" }, { content: "<p>step 1</p>" }],
},
quiz: {
questions: [
"<h2>Test quiz</h2><p>step 1</p><code class='language-python'>print('hello')</code>",
],
questionCount: 1,
currentQuestion: 0,
},
currentStepPosition: 1,
},
};
const store = mockStore(initialState);
render(
<Provider store={store}>
<InstructionsPanel />
</Provider>,
);
});

test("Renders the quiz content", () => {
expect(screen.queryByText("Test quiz")).toBeInTheDocument();
});

test("Scrolls instructions to the top", () => {
expect(window.HTMLElement.prototype.scrollTo).toHaveBeenCalledWith({
top: 0,
});
});

test("Removes the progress bar", () => {
expect(screen.queryByRole("progressbar")).not.toBeInTheDocument();
});

test("Applies syntax highlighting", () => {
const codeElement = document.getElementsByClassName("language-python")[0];
expect(window.Prism.highlightElement).toHaveBeenCalledWith(codeElement);
});
});
5 changes: 4 additions & 1 deletion src/redux/reducers/instructionsReducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ export const setCurrentStepPosition = (state, action) => {
state.currentStepPosition = action.payload;
};

export const reducers = { setInstructions, setCurrentStepPosition };
export const reducers = {
setInstructions,
setCurrentStepPosition,
};
25 changes: 20 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@
resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-10.5.0.tgz#0ee36f65b49b447fbac71b9e5af5c5c6c98ac057"
integrity sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==

"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.3.2":
"@codemirror/autocomplete@^6.0.0":
version "6.7.0"
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.7.0.tgz#8cc6ec437beb2aafd3186d63cb475c30ba3aa3c3"
integrity sha512-di5NFfxuG3c2dllwb33Zyw6Qsmo/W+cFCO2JzBPZLWlLSkgKQfr+r0Kf3qK1b/TwkQ3MbnBQY8Z01hkSYX6Qfw==
Expand All @@ -1153,6 +1153,16 @@
"@codemirror/view" "^6.6.0"
"@lezer/common" "^1.0.0"

"@codemirror/autocomplete@^6.3.2":
version "6.11.1"
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.11.1.tgz#c733900eee58ac2de817317b9fd1e91b857c4329"
integrity sha512-L5UInv8Ffd6BPw0P3EF7JLYAMeEbclY7+6Q11REt8vhih8RuLreKtPy/xk8wPxs4EQgYqzI7cdgpiYwWlbS/ow==
dependencies:
"@codemirror/language" "^6.0.0"
"@codemirror/state" "^6.0.0"
"@codemirror/view" "^6.17.0"
"@lezer/common" "^1.0.0"

"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.1.1":
version "6.2.4"
resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.2.4.tgz#b8a0e5ce72448c092ba4c4b1d902e6f183948aec"
Expand Down Expand Up @@ -1215,7 +1225,7 @@
"@lezer/common" "^1.0.0"
"@lezer/javascript" "^1.0.0"

"@codemirror/lang-python@^6.0.2":
"@codemirror/lang-python@6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@codemirror/lang-python/-/lang-python-6.1.2.tgz#cabb57529679981f170491833dbf798576e7ab18"
integrity sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==
Expand Down Expand Up @@ -1716,9 +1726,9 @@
"@lezer/common" "^1.0.0"

"@lezer/python@^1.0.0":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@lezer/python/-/python-1.1.5.tgz#653128db6846dad0ecfc3650b39734212c724254"
integrity sha512-h0DVr6IfrmKUbTc5PeetaC87IZYoHyn5JogsVYW5mRDpVRyEsvaLBMLyEN4Ufc2BKp1c9y2Pkr8ZNLxS8dTLsQ==
version "1.1.9"
resolved "https://registry.yarnpkg.com/@lezer/python/-/python-1.1.9.tgz#fae1991b242d0ea7c605189c2655063386d58763"
integrity sha512-8Ua3p8NdICXR6qWvRCnCx5CI1B0DklZGNtRLwOrIS/OHecHIugRHZyr0NsaaQO2H2Nn34EPlRtltXIirLsry5Q==
dependencies:
"@lezer/highlight" "^1.0.0"
"@lezer/lr" "^1.0.0"
Expand Down Expand Up @@ -11197,6 +11207,11 @@ pretty-format@^29.0.0, pretty-format@^29.2.1, pretty-format@^29.5.0:
ansi-styles "^5.0.0"
react-is "^18.0.0"

prismjs@^1.29.0:
version "1.29.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==

process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
Expand Down

0 comments on commit c695239

Please sign in to comment.