Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
50 changes: 40 additions & 10 deletions public/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,50 @@
},
"instructionsPanel": {
"demoInstructions": {
"title": "How instructions work",
"enablingInstructions": "Enabling instructions",
"visible": "Any text written here will be visible to students in the sidebar.",
"writingInstructions": "Writing instructions",
"markdown": "Write your instructions using [Markdown](https://www.markdownguide.org/).",
"whatYouCanDo": "What you can do",
"lists": "Lists",
"bulletPoints": "Bullet points",
"numberedSteps": "Numbered steps"
"title": "How to use instructions",
"replaceThisText": "Replace this text with your own instructions. Anything you write here appears in the sidebar for your students.",
"writtenInMarkdown": "Instructions are written in Markdown. Switch between the **Edit** and **View** tabs to see how each example below was written, or read our [instructions guide](https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions).",
"studentCopyWarning": "Students get their own copy of a project when they start it, so changes you make later will not reach anyone who has already started.",
"formattingTextHeading": "Formatting text",
"bold": "**Bold text** draws attention to a word.",
"italic": "_Italic text_ is useful for emphasis.",
"boldItalic": "**_Bold and italic_** works too.",
"strikethrough": "~~Strikethrough~~ shows something that has changed.",
"lineBreaks": "A backslash at the end of a line starts a new line, as above. A blank line starts a new paragraph. Three dashes on their own line draw a divider, like the one above.",
"headingsHeading": "Headings",
"headings": "Start a line with `##`, and add more `#` characters for smaller headings β€” like the headings in this document.",
"listsHeading": "Lists",
"addSprite": "Add a sprite",
"addBackdrop": "Add a backdrop",
"nestList": "Indent by two spaces to put a list inside a list",
"openFile": "Open the file `main.py`",
"typeCode": "Type your code",
"clickRun": "Click **Run**",
"linksHeading": "Links",
"links": "Link to a website like this: [Raspberry Pi Foundation](https://www.raspberrypi.org).",
"codeHeading": "Code",
"codeIntro": "In Python and Web projects you might want to include some example code in your instructions.",
"inlineCode": "Use single backticks for code in a sentence:",
"inlineCodeExample": "The `print()` function shows a message.",
"codeBlocks": "For longer code, use three backticks and name the language. `python`, `html`, `css` or `javascript`:",
"pythonPrompt": "What is your name?",
"pythonNameVar": "name",
"pythonGreeting": "Hello, ",
"blocksHeading": "Blocks code",
"blocksIntro": "In a Blocks project you might want to reference a particular type of block in your instructions. You can highlight words with the same colour that's used for the block type itself:",
"blocksColourExample": "Get a block from the `Looks`{:block-type=\"looks\"} section.",
"blocksTypes": "The [instructions guide](https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions#h_01M0034Z2SSTYV4W3CQZ4JCV3A) lists all types you can use.",
"blocksExample": "You might also want to include an example of blocks. To do this use `blocks` as the language name in a code block:",
"blocksGreeting": "Hello!",
"blockSyntaxReference": "For more information on how to write blocks as text, see the [block syntax reference](https://en.scratch-wiki.info/wiki/Block_Plugin/Syntax).",
"turningOffFormattingHeading": "Turning off formatting",
"turningOffFormatting": "\\_A backslash before a symbol stops it formatting\\_, so this is not italic."
},
"emptyState": {
"addInstructions": "Add instructions",
"edits": "Like project code, students will not see any edits you make to the instructions after they have saved their version of the project.",
"location": "These instructions will be shown to students in their project sidebar and will be view-only.",
"markdown": "Instructions are written in <0>markdown</0>.",
"markdown": "Instructions are written in markdown. See our <0>guide</0> for more help",
"purpose": "Instructions can be added to your project to guide students."
},
"addStep": "Add a step",
Expand All @@ -120,6 +149,7 @@
"previousStep": "Previous step",
"stepCounter": "{{currentStep}} of {{totalSteps}}",
"projectSteps": "Project instructions",
"guideLink": "View instructions guide",
"edit": "Edit",
"view": "View",
"removeStepModal": {
Expand Down
73 changes: 63 additions & 10 deletions src/assets/markdown/demoInstructions.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,72 @@
# {{instructionsPanel.demoInstructions.title}}

## {{instructionsPanel.demoInstructions.enablingInstructions}}
{{instructionsPanel.demoInstructions.replaceThisText}}

{{instructionsPanel.demoInstructions.visible}}
{{instructionsPanel.demoInstructions.writtenInMarkdown}}

## {{instructionsPanel.demoInstructions.writingInstructions}}
**{{instructionsPanel.demoInstructions.studentCopyWarning}}**

{{instructionsPanel.demoInstructions.markdown}}
---

### {{instructionsPanel.demoInstructions.whatYouCanDo}}
## {{instructionsPanel.demoInstructions.formattingTextHeading}}

{{instructionsPanel.demoInstructions.lists}}:
{{instructionsPanel.demoInstructions.bold}}\
{{instructionsPanel.demoInstructions.italic}}\
{{instructionsPanel.demoInstructions.boldItalic}}\
{{instructionsPanel.demoInstructions.strikethrough}}

- {{instructionsPanel.demoInstructions.bulletPoints}}
- {{instructionsPanel.demoInstructions.bulletPoints}}
{{instructionsPanel.demoInstructions.lineBreaks}}

1. {{instructionsPanel.demoInstructions.numberedSteps}}
2. {{instructionsPanel.demoInstructions.numberedSteps}}
## {{instructionsPanel.demoInstructions.headingsHeading}}

{{instructionsPanel.demoInstructions.headings}}

## {{instructionsPanel.demoInstructions.listsHeading}}

- {{instructionsPanel.demoInstructions.addSprite}}
- {{instructionsPanel.demoInstructions.addBackdrop}}
- {{instructionsPanel.demoInstructions.nestList}}

1. {{instructionsPanel.demoInstructions.openFile}}
2. {{instructionsPanel.demoInstructions.typeCode}}
3. {{instructionsPanel.demoInstructions.clickRun}}

## {{instructionsPanel.demoInstructions.linksHeading}}

{{instructionsPanel.demoInstructions.links}}

## {{instructionsPanel.demoInstructions.codeHeading}}

{{instructionsPanel.demoInstructions.codeIntro}}

{{instructionsPanel.demoInstructions.inlineCode}}

{{instructionsPanel.demoInstructions.inlineCodeExample}}

{{instructionsPanel.demoInstructions.codeBlocks}}

```python
{{instructionsPanel.demoInstructions.pythonNameVar}} = input("{{instructionsPanel.demoInstructions.pythonPrompt}} ")
print("{{instructionsPanel.demoInstructions.pythonGreeting}}" + {{instructionsPanel.demoInstructions.pythonNameVar}})
```

## {{instructionsPanel.demoInstructions.blocksHeading}}

{{instructionsPanel.demoInstructions.blocksIntro}}

{{instructionsPanel.demoInstructions.blocksColourExample}}

{{instructionsPanel.demoInstructions.blocksTypes}}

{{instructionsPanel.demoInstructions.blocksExample}}

```blocks
when green flag clicked
say [{{instructionsPanel.demoInstructions.blocksGreeting}}] for (2) seconds
```

{{instructionsPanel.demoInstructions.blockSyntaxReference}}

## {{instructionsPanel.demoInstructions.turningOffFormattingHeading}}

{{instructionsPanel.demoInstructions.turningOffFormatting}}
8 changes: 8 additions & 0 deletions src/assets/stylesheets/InternalStyles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@

--editor-color-tab-background: var(--editor-color-layer-3);

// Design System

// Link (.rpf-link)

--link-color: var(--editor-color-theme);
--link-color-hover: color-mix(in srgb, var(--editor-color-theme), white 15%);
--link-color-active: color-mix(in srgb, var(--editor-color-theme), white 30%);

// Primary button
--rpf-button-text-color: var(--rpf-black);
--rpf-button-background-color: var(--editor-color-theme);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import InstructionsStep from "./InstructionsStep/InstructionsStep";
import ProgressBar from "./ProgressBar/ProgressBar";
import BinIcon from "../../../../assets/icons/bin.svg";

const INSTRUCTIONS_GUIDE_URL =
"https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions";

const InstructionsPanel = () => {
const [tabIndex, setTabIndex] = useState(0);
const [showRemoveStepModal, setShowRemoveStepModal] = useState(false);
Expand Down Expand Up @@ -106,6 +109,18 @@ const InstructionsPanel = () => {
]
: []
}
headerContent={
instructionsEditable && hasInstructions ? (
<a
className="rpf-link"
href={INSTRUCTIONS_GUIDE_URL}
target="_blank"
rel="noreferrer"
>
{t("instructionsPanel.guideLink")}
</a>
) : undefined
}
Footer={
hasInstructions && (hasMultipleSteps || onEditTab)
? () => <ProgressBar panelRef={panelRef} />
Expand Down Expand Up @@ -173,7 +188,7 @@ const InstructionsPanel = () => {
i18nKey="instructionsPanel.emptyState.markdown"
components={[
<a
href="https://www.markdownguide.org/cheat-sheet/"
href="https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions"
target="_blank"
rel="noreferrer"
/>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ describe("When instructionsEditable is true", () => {
screen.queryByText("instructionsPanel.emptyState.addInstructions"),
).not.toBeInTheDocument();
});

test("Renders a link to the how to write instructions guide", () => {
const link = screen.getByRole("link", {
name: "instructionsPanel.guideLink",
});

expect(link).toHaveAttribute(
"href",
"https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions",
);
expect(link).toHaveAttribute("target", "_blank");
});
});

describe("Adding and removing steps", () => {
Expand Down Expand Up @@ -268,6 +280,7 @@ describe("When instructionsEditable is true", () => {
instructionsEditable: true,
},
instructions: {
permitOverride: true,
project: {
steps: [],
},
Expand Down Expand Up @@ -301,6 +314,24 @@ describe("When instructionsEditable is true", () => {
screen.queryByText("instructionsPanel.emptyState.purpose"),
).toBeInTheDocument();
});

test("Does not render the guide link in the panel header", () => {
expect(
screen.queryByRole("link", { name: "instructionsPanel.guideLink" }),
).not.toBeInTheDocument();
});

test("Adding instructions reveals the guide link", () => {
act(() => {
fireEvent.click(
screen.getByText("instructionsPanel.emptyState.addInstructions"),
);
});

expect(
screen.getByRole("link", { name: "instructionsPanel.guideLink" }),
).toBeInTheDocument();
});
});
});

Expand Down Expand Up @@ -335,6 +366,12 @@ describe("When instructions are not editable", () => {
).not.toBeInTheDocument();
});

test("Does not render the how to write instructions guide link", () => {
expect(
screen.queryByRole("link", { name: "instructionsPanel.guideLink" }),
).not.toBeInTheDocument();
});

test("It renders without crashing", () => {
expect(
screen.queryByText("instructionsPanel.projectSteps"),
Expand Down Expand Up @@ -390,6 +427,12 @@ describe("When instructions are not editable", () => {
});
});

test("Does not render the how to write instructions guide link", () => {
expect(
screen.queryByRole("link", { name: "instructionsPanel.guideLink" }),
).not.toBeInTheDocument();
});

test("Renders no tab titles", () => {
expect(screen.queryAllByRole("tab")).toHaveLength(0);
});
Expand Down
3 changes: 3 additions & 0 deletions src/components/Menus/Sidebar/SidebarPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const SidebarPanel = (props) => {
Footer,
className,
buttons,
headerContent,
panelRef,
defaultWidth = "320px",
} = props;
Expand All @@ -27,6 +28,7 @@ const SidebarPanel = (props) => {
{buttons && !buttonsIsEmptyArray && (
<div className="sidebar__panel-buttons">{buttons}</div>
)}
{headerContent}
</div>
<div ref={panelRef} className="sidebar__panel-content">
{children}
Expand Down Expand Up @@ -62,6 +64,7 @@ SidebarPanel.propTypes = {
heading: PropTypes.string.isRequired,
className: PropTypes.string,
buttons: PropTypes.arrayOf(PropTypes.node),
headerContent: PropTypes.node,
};

export default SidebarPanel;
23 changes: 23 additions & 0 deletions src/components/Menus/Sidebar/SidebarPanel.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,29 @@ test("Renders a single button", () => {
expect(screen.queryByText("button")).toBeInTheDocument();
});

test("Renders arbitrary header content", () => {
render(
<SidebarPanel heading="heading" headerContent={<a href="/x">a link</a>}>
some content
</SidebarPanel>,
);
expect(screen.queryByRole("link", { name: "a link" })).toBeInTheDocument();
});

test("Renders header content alongside buttons", () => {
render(
<SidebarPanel
heading="heading"
buttons={[<button key="1">button</button>]}
headerContent={<p>header note</p>}
>
some content
</SidebarPanel>,
);
expect(screen.queryByText("button")).toBeInTheDocument();
expect(screen.queryByText("header note")).toBeInTheDocument();
});

test("Renders multiple buttons", () => {
render(
<SidebarPanel
Expand Down
Loading