From 4e09d6a2bc9b72d8dedc09365d61ce19758536cc Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Tue, 18 Aug 2026 15:42:28 +0100 Subject: [PATCH 01/10] Let sidebar panels pass arbitrary content into their header Panels could only add buttons to their header. A `headerContent` node prop lets a panel put anything else there - a link, status text, a filter control - rendered as-is below the heading and buttons, with the panel owning its styling. The alternative was to keep reusing the existing `buttons` slot, which does accept arbitrary nodes, but it is named and laid out for buttons and forms part of the host sidebar-plugin contract, so overloading it would blur both. `buttons` is left untouched, so the other panels and existing plugins are unaffected. Co-Authored-By: Claude Opus 5 --- src/components/Menus/Sidebar/SidebarPanel.jsx | 3 +++ .../Menus/Sidebar/SidebarPanel.test.jsx | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/components/Menus/Sidebar/SidebarPanel.jsx b/src/components/Menus/Sidebar/SidebarPanel.jsx index d147f2de1..713eead77 100644 --- a/src/components/Menus/Sidebar/SidebarPanel.jsx +++ b/src/components/Menus/Sidebar/SidebarPanel.jsx @@ -12,6 +12,7 @@ const SidebarPanel = (props) => { Footer, className, buttons, + headerContent, panelRef, defaultWidth = "320px", } = props; @@ -27,6 +28,7 @@ const SidebarPanel = (props) => { {buttons && !buttonsIsEmptyArray && (
{buttons}
)} + {headerContent}
{children} @@ -62,6 +64,7 @@ SidebarPanel.propTypes = { heading: PropTypes.string.isRequired, className: PropTypes.string, buttons: PropTypes.arrayOf(PropTypes.node), + headerContent: PropTypes.node, }; export default SidebarPanel; diff --git a/src/components/Menus/Sidebar/SidebarPanel.test.jsx b/src/components/Menus/Sidebar/SidebarPanel.test.jsx index f1ec1ee36..7555eab66 100644 --- a/src/components/Menus/Sidebar/SidebarPanel.test.jsx +++ b/src/components/Menus/Sidebar/SidebarPanel.test.jsx @@ -33,6 +33,29 @@ test("Renders a single button", () => { expect(screen.queryByText("button")).toBeInTheDocument(); }); +test("Renders arbitrary header content", () => { + render( + a link}> + some content + , + ); + expect(screen.queryByRole("link", { name: "a link" })).toBeInTheDocument(); +}); + +test("Renders header content alongside buttons", () => { + render( + button]} + headerContent={

header note

} + > + some content +
, + ); + expect(screen.queryByText("button")).toBeInTheDocument(); + expect(screen.queryByText("header note")).toBeInTheDocument(); +}); + test("Renders multiple buttons", () => { render( Date: Tue, 18 Aug 2026 15:42:28 +0100 Subject: [PATCH 02/10] Link teachers to the project instructions guide Teachers writing project instructions had no pointer from the editor to the help centre guide on how to write them, so the instructions panel header now links to it. The link is gated on `instructionsEditable` rather than a new teacher flag. There is no role concept in this codebase; hosts set `editable_instructions` only for people authoring instructions, so it is already the de facto teacher signal, and reusing it keeps the gate consistent with the rest of the panel's edit UI. A dedicated attribute would have meant plumbing through web-component.jsx, WebComponentLoader and WebComponentProject for no difference in behaviour today. Styled with the design system's `rpf-link` rather than a bespoke class, so it picks up link colours and focus states in both themes for free. Co-Authored-By: Claude Opus 5 --- public/translations/en.json | 1 + .../InstructionsPanel/InstructionsPanel.jsx | 15 ++++++++++ .../InstructionsPanel.test.jsx | 30 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/public/translations/en.json b/public/translations/en.json index eec4fa86a..8f48a4f08 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -120,6 +120,7 @@ "previousStep": "Previous step", "stepCounter": "{{currentStep}} of {{totalSteps}}", "projectSteps": "Project instructions", + "guideLink": "View instructions guide", "edit": "Edit", "view": "View", "removeStepModal": { diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx index 00e85325e..a78356e8b 100644 --- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx +++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx @@ -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); @@ -106,6 +109,18 @@ const InstructionsPanel = () => { ] : [] } + headerContent={ + instructionsEditable ? ( + + {t("instructionsPanel.guideLink")} + + ) : undefined + } Footer={ hasInstructions && (hasMultipleSteps || onEditTab) ? () => diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx index bf782bcf7..86dbd42b4 100644 --- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx +++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx @@ -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", () => { @@ -301,6 +313,12 @@ describe("When instructionsEditable is true", () => { screen.queryByText("instructionsPanel.emptyState.purpose"), ).toBeInTheDocument(); }); + + test("Renders a link to the how to write instructions guide", () => { + expect( + screen.getByRole("link", { name: "instructionsPanel.guideLink" }), + ).toBeInTheDocument(); + }); }); }); @@ -335,6 +353,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"), @@ -390,6 +414,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); }); From 5b64c83bb393fc7d27550a467df797cf8a2ebcb4 Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Wed, 19 Aug 2026 09:53:32 +0100 Subject: [PATCH 03/10] Rewrite the demo instructions to teach Markdown by example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The demo instructions a teacher gets when they first enable instructions described three Markdown features and demonstrated none of them. Because the panel renders the content, the document can be its own worked example: a teacher toggling between Edit and View sees the syntax and the result side by side, with no screenshots to keep in sync. The rewrite covers every feature the renderer actually supports — text styling, headings, paragraphs and line breaks, lists, links, inline code, code blocks, block-type colouring, real blocks, and escaping — and opens by telling the teacher to replace the text, since many will start typing at the top and never scroll. Every line of prose is a translation key, so translators receive whole sentences rather than fragments to reassemble. The alternative was keeping the Markdown markers in the template and keying only the words between them, which would stop a translator breaking a `**` pair, but it splits most sentences into two or three keys and makes the template hard to read. Whole lines won on clarity. The human-facing strings inside the two code examples are translated too, but the surrounding code is not: scratchblocks only draws real blocks when the block wording matches the editor exactly, so a translated `say` or `when green flag clicked` would render as an unrecognised grey block. The Python greeting uses an f-string, `print(f"{{...pythonGreeting}}")` with the key holding `Hello, {name}`, rather than the concatenation it replaces. Keying `"Hello, "` for use with `+ name` would have put grammar in the template and a trailing space at the end of a translation string, where it is likely to be trimmed. The f-string hands the translator the punctuation, the spacing and the word order together. `populateMarkdownTemplate` only substitutes double-braced placeholders, so the single-braced `{name}` reaches the rendered Python untouched. Only en.json is updated; Crowdin overwrites the other locales, and missing keys fall back to English until it syncs. Co-Authored-By: Claude Opus 5 --- public/translations/en.json | 43 ++++++++++++---- src/assets/markdown/demoInstructions.md | 67 +++++++++++++++++++++---- 2 files changed, 91 insertions(+), 19 deletions(-) diff --git a/public/translations/en.json b/public/translations/en.json index 8f48a4f08..24d802f12 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -96,15 +96,40 @@ }, "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": "Project 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", + "inlineCode": "Use single backticks for code in a sentence: 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?", + "pythonGreeting": "Hello, {name}", + "colouringHeading": "Colouring words like blocks", + "colouring": "Colour a word to match a block category: get a block from the `Looks`{:block-type=\"looks\"} section. The [instructions guide](https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions#h_01M0034Z2SSTYV4W3CQZ4JCV3A) lists all ten categories you can use.", + "realBlocksHeading": "Showing real blocks", + "realBlocks": "Use `blocks` as the language name:", + "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", diff --git a/src/assets/markdown/demoInstructions.md b/src/assets/markdown/demoInstructions.md index c27b9ecca..77d39a273 100644 --- a/src/assets/markdown/demoInstructions.md +++ b/src/assets/markdown/demoInstructions.md @@ -1,19 +1,66 @@ # {{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.inlineCode}} + +{{instructionsPanel.demoInstructions.codeBlocks}} + +```python +name = input("{{instructionsPanel.demoInstructions.pythonPrompt}} ") +print(f"{{instructionsPanel.demoInstructions.pythonGreeting}}") +``` + +## {{instructionsPanel.demoInstructions.colouringHeading}} + +{{instructionsPanel.demoInstructions.colouring}} + +## {{instructionsPanel.demoInstructions.realBlocksHeading}} + +{{instructionsPanel.demoInstructions.realBlocks}} + +```blocks +when green flag clicked +say [{{instructionsPanel.demoInstructions.blocksGreeting}}] for (2) seconds +``` + +{{instructionsPanel.demoInstructions.blockSyntaxReference}} + +## {{instructionsPanel.demoInstructions.turningOffFormattingHeading}} + +{{instructionsPanel.demoInstructions.turningOffFormatting}} From 1f547e3d084359f2739d002a2e5110e7f9af25eb Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 11:25:34 +0100 Subject: [PATCH 04/10] fix: add variable name translation string for variable in demo instructions --- public/translations/en.json | 1 + src/assets/markdown/demoInstructions.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/public/translations/en.json b/public/translations/en.json index 24d802f12..7f84127cc 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -121,6 +121,7 @@ "inlineCode": "Use single backticks for code in a sentence: 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, {name}", "colouringHeading": "Colouring words like blocks", "colouring": "Colour a word to match a block category: get a block from the `Looks`{:block-type=\"looks\"} section. The [instructions guide](https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions#h_01M0034Z2SSTYV4W3CQZ4JCV3A) lists all ten categories you can use.", diff --git a/src/assets/markdown/demoInstructions.md b/src/assets/markdown/demoInstructions.md index 77d39a273..782b1d845 100644 --- a/src/assets/markdown/demoInstructions.md +++ b/src/assets/markdown/demoInstructions.md @@ -42,7 +42,7 @@ {{instructionsPanel.demoInstructions.codeBlocks}} ```python -name = input("{{instructionsPanel.demoInstructions.pythonPrompt}} ") +{{instructionsPanel.demoInstructions.pythonNameVar}} = input("{{instructionsPanel.demoInstructions.pythonPrompt}} ") print(f"{{instructionsPanel.demoInstructions.pythonGreeting}}") ``` From 71d5b955d6fb9bfc03b91da145e42059dbda872a Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 11:26:27 +0100 Subject: [PATCH 05/10] fix: change project demo instructions title to h2 --- src/assets/markdown/demoInstructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/markdown/demoInstructions.md b/src/assets/markdown/demoInstructions.md index 782b1d845..089ddaad5 100644 --- a/src/assets/markdown/demoInstructions.md +++ b/src/assets/markdown/demoInstructions.md @@ -1,4 +1,4 @@ -# {{instructionsPanel.demoInstructions.title}} +## {{instructionsPanel.demoInstructions.title}} {{instructionsPanel.demoInstructions.replaceThisText}} From 232c31d0e3d12c61b8539503ec75e8866f425dee Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 11:27:35 +0100 Subject: [PATCH 06/10] refactor: change title of demo instructions --- public/translations/en.json | 2 +- src/assets/markdown/demoInstructions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/translations/en.json b/public/translations/en.json index 7f84127cc..08cba3d45 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -96,7 +96,7 @@ }, "instructionsPanel": { "demoInstructions": { - "title": "Project instructions", + "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.", diff --git a/src/assets/markdown/demoInstructions.md b/src/assets/markdown/demoInstructions.md index 089ddaad5..782b1d845 100644 --- a/src/assets/markdown/demoInstructions.md +++ b/src/assets/markdown/demoInstructions.md @@ -1,4 +1,4 @@ -## {{instructionsPanel.demoInstructions.title}} +# {{instructionsPanel.demoInstructions.title}} {{instructionsPanel.demoInstructions.replaceThisText}} From f7e32c33d6328a73a89ff8f5f6b3f9c2287ae90e Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 11:32:04 +0100 Subject: [PATCH 07/10] feat: add dark theme for design system link --- src/assets/stylesheets/InternalStyles.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/assets/stylesheets/InternalStyles.scss b/src/assets/stylesheets/InternalStyles.scss index 9fdbb5f8a..59aa2557e 100644 --- a/src/assets/stylesheets/InternalStyles.scss +++ b/src/assets/stylesheets/InternalStyles.scss @@ -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); From b0f89ab9c92fc6117ac1e3b142417f603e5ffb89 Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 14:11:46 +0100 Subject: [PATCH 08/10] fix: reference the relevant project type in the demo instructions --- public/translations/en.json | 17 ++++++++++------- src/assets/markdown/demoInstructions.md | 16 +++++++++++----- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/public/translations/en.json b/public/translations/en.json index 08cba3d45..e3cbb3b77 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -118,15 +118,18 @@ "linksHeading": "Links", "links": "Link to a website like this: [Raspberry Pi Foundation](https://www.raspberrypi.org).", "codeHeading": "Code", - "inlineCode": "Use single backticks for code in a sentence: the `print()` function shows a message.", - "codeBlocks": "For longer code, use three backticks and name the language — `python`, `html`, `css` or `javascript`:", + "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, {name}", - "colouringHeading": "Colouring words like blocks", - "colouring": "Colour a word to match a block category: get a block from the `Looks`{:block-type=\"looks\"} section. The [instructions guide](https://help.editor.raspberrypi.org/hc/en-us/articles/52495086715028-How-to-write-project-instructions#h_01M0034Z2SSTYV4W3CQZ4JCV3A) lists all ten categories you can use.", - "realBlocksHeading": "Showing real blocks", - "realBlocks": "Use `blocks` as the language 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", diff --git a/src/assets/markdown/demoInstructions.md b/src/assets/markdown/demoInstructions.md index 782b1d845..722153be1 100644 --- a/src/assets/markdown/demoInstructions.md +++ b/src/assets/markdown/demoInstructions.md @@ -37,22 +37,28 @@ ## {{instructionsPanel.demoInstructions.codeHeading}} +{{instructionsPanel.demoInstructions.codeIntro}} + {{instructionsPanel.demoInstructions.inlineCode}} +{{instructionsPanel.demoInstructions.inlineCodeExample}} + {{instructionsPanel.demoInstructions.codeBlocks}} ```python {{instructionsPanel.demoInstructions.pythonNameVar}} = input("{{instructionsPanel.demoInstructions.pythonPrompt}} ") -print(f"{{instructionsPanel.demoInstructions.pythonGreeting}}") +print("{{instructionsPanel.demoInstructions.pythonGreeting}}" + {{instructionsPanel.demoInstructions.pythonNameVar}}) ``` -## {{instructionsPanel.demoInstructions.colouringHeading}} +## {{instructionsPanel.demoInstructions.blocksHeading}} + +{{instructionsPanel.demoInstructions.blocksIntro}} -{{instructionsPanel.demoInstructions.colouring}} +{{instructionsPanel.demoInstructions.blocksColourExample}} -## {{instructionsPanel.demoInstructions.realBlocksHeading}} +{{instructionsPanel.demoInstructions.blocksTypes}} -{{instructionsPanel.demoInstructions.realBlocks}} +{{instructionsPanel.demoInstructions.blocksExample}} ```blocks when green flag clicked From 275cba2eaa426bf14dcf0370ce1c044134eb5d82 Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 14:16:45 +0100 Subject: [PATCH 09/10] refactor: only show guide link in the header when instructions have been added. Reference in the empty state. --- public/translations/en.json | 2 +- .../Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/translations/en.json b/public/translations/en.json index e3cbb3b77..1c7a8e45f 100644 --- a/public/translations/en.json +++ b/public/translations/en.json @@ -139,7 +139,7 @@ "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.", + "markdown": "Instructions are written in markdown. See our <0>guide for more help", "purpose": "Instructions can be added to your project to guide students." }, "addStep": "Add a step", diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx index a78356e8b..e9f53558d 100644 --- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx +++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.jsx @@ -110,7 +110,7 @@ const InstructionsPanel = () => { : [] } headerContent={ - instructionsEditable ? ( + instructionsEditable && hasInstructions ? ( { i18nKey="instructionsPanel.emptyState.markdown" components={[ , From 4e9b551634322c55113231d1dc38b1ecc451ddbd Mon Sep 17 00:00:00 2001 From: Max Elkins Date: Thu, 20 Aug 2026 14:35:10 +0100 Subject: [PATCH 10/10] test: update tests related to guide links --- .../InstructionsPanel/InstructionsPanel.test.jsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx index 86dbd42b4..bfa47f5e8 100644 --- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx +++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx @@ -280,6 +280,7 @@ describe("When instructionsEditable is true", () => { instructionsEditable: true, }, instructions: { + permitOverride: true, project: { steps: [], }, @@ -314,7 +315,19 @@ describe("When instructionsEditable is true", () => { ).toBeInTheDocument(); }); - test("Renders a link to the how to write instructions guide", () => { + 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();