diff --git a/docs/writing-docs/tutorials/control-options.md b/docs/writing-docs/tutorials/control-options.md index 1511497d5778..025be0e4b473 100644 --- a/docs/writing-docs/tutorials/control-options.md +++ b/docs/writing-docs/tutorials/control-options.md @@ -62,6 +62,14 @@ For text-based tutorials, you can choose to hide the toolbox altogether. This is ### @hideToolbox true ``` +### Hide Done + +If you do not wish for your tutorial's final step to display a "Done" button, which sends the user back to the main editor, you can hide it by specifying **@hideDone** in the metadata. The default is ``false``. + +``` +### @hideDone true +``` + ## Special blocks ### Templates diff --git a/localtypings/pxtarget.d.ts b/localtypings/pxtarget.d.ts index feb1d9700a61..d0f1f29e7f15 100644 --- a/localtypings/pxtarget.d.ts +++ b/localtypings/pxtarget.d.ts @@ -1205,6 +1205,7 @@ declare namespace pxt.tutorial { codeStop?: string; // command to run when code stops (MINECRAFT HOC ONLY) autoexpandOff?: boolean; // INTERNAL TESTING ONLY preferredEditor?: string; // preferred editor for opening the tutorial + hideDone?: boolean; // Do not show a "Done" button at the end of the tutorial } interface TutorialBlockConfigEntry { diff --git a/package.json b/package.json index d145f350562b..fb191be60c2d 100644 --- a/package.json +++ b/package.json @@ -164,6 +164,7 @@ "test:err": "gulp testerr", "test:fmt": "gulp testfmt", "test:lang": "gulp testlang", + "test:tutorials": "gulp testtutorials", "update": "gulp update", "watch-streamer": "cd docs/static/streamer && tsc -t es6 --watch", "prepare": "node ./scripts/npm-prepare.js", diff --git a/tests/tutorial-test/baselines/hideDone.json b/tests/tutorial-test/baselines/hideDone.json new file mode 100644 index 000000000000..a46227a2e28a --- /dev/null +++ b/tests/tutorial-test/baselines/hideDone.json @@ -0,0 +1,23 @@ +{ + "editor": "blocksprj", + "title": "Hide Done", + "steps": [ + { + "contentMd": "Tutorials can choose to hide the done button on the final step. This metadata is parsed and removed.", + "headerContentMd": "Tutorials can choose to hide the done button on the final step. This metadata is parsed and removed." + }, + { + "contentMd": "Tutorial parsing for hints, steps, etc should function exactly as before.\n\n```blocks\nlet x = 8;\nlet y = x + 2;\n```", + "headerContentMd": "Tutorial parsing for hints, steps, etc should function exactly as before.", + "hintContentMd": "```blocks\nlet x = 8;\nlet y = x + 2;\n```" + } + ], + "activities": null, + "code": [ + "{\nlet x = 8;\nlet y = x + 2;\n}", + "{\nbasic.showIcon(IconNames.Square)\n}" + ], + "metadata": { + "hideDone": true + } +} diff --git a/tests/tutorial-test/baselines/hideToolbox.json b/tests/tutorial-test/baselines/hideToolbox.json new file mode 100644 index 000000000000..02a569e2a970 --- /dev/null +++ b/tests/tutorial-test/baselines/hideToolbox.json @@ -0,0 +1,23 @@ +{ + "editor": "blocksprj", + "title": "Hide Toolbox", + "steps": [ + { + "contentMd": "Tutorials can choose to hide the toolbox. This metadata is parsed and removed.", + "headerContentMd": "Tutorials can choose to hide the toolbox. This metadata is parsed and removed." + }, + { + "contentMd": "Tutorial parsing for hints, steps, etc should function exactly as before.\n\n```blocks\nlet x = 8;\nlet y = x + 2;\n```", + "headerContentMd": "Tutorial parsing for hints, steps, etc should function exactly as before.", + "hintContentMd": "```blocks\nlet x = 8;\nlet y = x + 2;\n```" + } + ], + "activities": null, + "code": [ + "{\nlet x = 8;\nlet y = x + 2;\n}", + "{\nbasic.showIcon(IconNames.Square)\n}" + ], + "metadata": { + "hideToolbox": true + } +} diff --git a/tests/tutorial-test/cases/hideDone.md b/tests/tutorial-test/cases/hideDone.md new file mode 100644 index 000000000000..6596085a2ff4 --- /dev/null +++ b/tests/tutorial-test/cases/hideDone.md @@ -0,0 +1,20 @@ +# Hide Done + +### @hideDone true + +## Introduction + +Tutorials can choose to hide the done button on the final step. This metadata is parsed and removed. + +## Step with hint + +Tutorial parsing for hints, steps, etc should function exactly as before. + +```blocks +let x = 8; +let y = x + 2; +``` + +```ghost +basic.showIcon(IconNames.Square) +``` diff --git a/tests/tutorial-test/cases/hideToolbox.md b/tests/tutorial-test/cases/hideToolbox.md new file mode 100644 index 000000000000..4bf31af59ad6 --- /dev/null +++ b/tests/tutorial-test/cases/hideToolbox.md @@ -0,0 +1,20 @@ +# Hide Toolbox + +### @hideToolbox true + +## Introduction + +Tutorials can choose to hide the toolbox. This metadata is parsed and removed. + +## Step with hint + +Tutorial parsing for hints, steps, etc should function exactly as before. + +```blocks +let x = 8; +let y = x + 2; +``` + +```ghost +basic.showIcon(IconNames.Square) +``` diff --git a/webapp/src/components/tutorial/TutorialContainer.tsx b/webapp/src/components/tutorial/TutorialContainer.tsx index 4f2d26957bad..e3b2f995b1c3 100644 --- a/webapp/src/components/tutorial/TutorialContainer.tsx +++ b/webapp/src/components/tutorial/TutorialContainer.tsx @@ -49,7 +49,7 @@ export function TutorialContainer(props: TutorialContainerProps) { const showBack = currentStep !== 0; const showNext = currentStep !== steps.length - 1; - const showDone = !showNext && !pxt.appTarget.appTheme.lockedEditor && !hideIteration; + const isDone = !showNext && !pxt.appTarget.appTheme.lockedEditor && !hideIteration; const showImmersiveReader = pxt.appTarget.appTheme.immersiveReader; const isHorizontal = props.tutorialSimSidebar || pxt.BrowserUtils.isTabletSize(); @@ -235,10 +235,11 @@ export function TutorialContainer(props: TutorialContainerProps) { }) } + const hideDone = tutorialOptions.metadata?.hideDone; const doneButtonLabel = lf("Finish the tutorial."); const nextButtonLabel = lf("Go to the next step of the tutorial."); - const nextButton = showDone - ?