Skip to content

Commit

Permalink
Add "Hide Done" Option for Tutorials (#10248)
Browse files Browse the repository at this point in the history
This adds a "hideDone" flag that can be set on a tutorial to indicate that the Done button should not be shown on the final step.

Also added tests for hideDone and hideToolbox (which I added in 9e6dd9e). Not sure how much value they bring beyond parsing validation, but I suppose that's better than nothing!
  • Loading branch information
thsparks committed Oct 31, 2024
1 parent 499167a commit 59a2b47
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 11 deletions.
16 changes: 16 additions & 0 deletions docs/writing-docs/tutorials/control-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ You can highlight the differences in code between the current step hint and the
### @diffs true
```

### Hide Toolbox

For text-based tutorials, you can choose to hide the toolbox altogether. This is done by specifying **@hideToolbox** in the metadata. The default is ``false``.

```
### @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
Expand Down
3 changes: 2 additions & 1 deletion localtypings/pxtarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ declare namespace pxt.tutorial {
autoexpandOff?: boolean; // INTERNAL TESTING ONLY
preferredEditor?: string; // preferred editor for opening the tutorial
tutorialCodeValidation?: boolean; // enable tutorial validation for this tutorial
hideDone?: boolean; // Do not show a "Done" button at the end of the tutorial
}

interface TutorialRuleStatus {
Expand Down Expand Up @@ -1278,4 +1279,4 @@ declare namespace pxt.auth {
type: "skillmap-completion";
sourceURL: string;
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,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": "cd skillmap && npm install && cd .. && cd authcode && npm install && cd .. && cd multiplayer && npm install && cd .. && cd kiosk && npm install && cd .."
Expand Down
23 changes: 23 additions & 0 deletions tests/tutorial-test/baselines/hideDone.json
Original file line number Diff line number Diff line change
@@ -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
}
}
23 changes: 23 additions & 0 deletions tests/tutorial-test/baselines/hideToolbox.json
Original file line number Diff line number Diff line change
@@ -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
}
}
20 changes: 20 additions & 0 deletions tests/tutorial-test/cases/hideDone.md
Original file line number Diff line number Diff line change
@@ -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)
```
20 changes: 20 additions & 0 deletions tests/tutorial-test/cases/hideToolbox.md
Original file line number Diff line number Diff line change
@@ -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)
```
12 changes: 7 additions & 5 deletions webapp/src/components/tutorial/TutorialContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,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 = layout === "horizontal";

Expand Down Expand Up @@ -226,18 +226,20 @@ 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
? <Button icon="check circle" title={doneButtonLabel} ariaLabel={doneButtonLabel} text={lf("Done")} onClick={onTutorialComplete} />
const nextButton = isDone
? hideDone ? null : <Button icon="check circle" title={doneButtonLabel} ariaLabel={doneButtonLabel} text={lf("Done")} onClick={onTutorialComplete} />
: <Button icon="arrow circle right" title={nextButtonLabel} ariaLabel={nextButtonLabel} disabled={!showNext} text={lf("Next")} onClick={() => validateTutorialStep()} />;

const stepCounter = <TutorialStepCounter
tutorialId={tutorialId}
currentStep={visibleStep}
totalSteps={steps.length}
title={name}
setTutorialStep={handleStepCounterSetStep} />;
setTutorialStep={handleStepCounterSetStep}
hideDone={hideDone} />;
const hasHint = !!hintMarkdown;


Expand Down Expand Up @@ -273,4 +275,4 @@ export function TutorialContainer(props: TutorialContainerProps) {
<MarkedContent markdown={currentStepInfo.contentMd} parent={parent} />
</Modal>}
</div>
}
}
10 changes: 6 additions & 4 deletions webapp/src/components/tutorial/TutorialStepCounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ interface TutorialStepCounterProps {
currentStep: number;
totalSteps: number;
title?: string;
hideDone?: boolean;
setTutorialStep: (step: number) => void;
}

Expand Down Expand Up @@ -35,9 +36,10 @@ export function TutorialStepCounter(props: TutorialStepCounterProps) {
setTutorialStep(step);
}

const lastStep = currentStep == totalSteps - 1;
const stepButtonLabelText = (step: number) => lf("Go to step {0} of {1}", step + 1, totalSteps);
const backButtonLabel = lf("Go to the previous step of the tutorial.");
const nextButtonLabel = lf("Go to the next step of the tutorial.");
const showNextButton = !lastStep || !props.hideDone;

return <div className="tutorial-step-counter">
<div className="tutorial-step-label">
Expand Down Expand Up @@ -65,14 +67,14 @@ export function TutorialStepCounter(props: TutorialStepCounterProps) {
label={stepNum === currentStep ? `${stepNum + 1}` : undefined}
/>
})}
<Button
{showNextButton && <Button
disabled={currentStep == totalSteps - 1}
className="square-button"
leftIcon="icon right chevron"
onClick={handleNextStep}
aria-label={nextButtonLabel}
title={nextButtonLabel}
/>
/>}
</div>
</div>
}
}
3 changes: 2 additions & 1 deletion webapp/src/tutorial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -711,9 +711,10 @@ export class TutorialCard extends data.Component<TutorialCardProps, TutorialCard
const currentStep = tutorialStep;
const maxSteps = tutorialStepInfo.length;
const hideIteration = metadata && metadata.hideIteration;
const hideDone = metadata && metadata.hideDone;
const hasPrevious = tutorialReady && currentStep != 0 && !hideIteration;
const hasNext = tutorialReady && currentStep != maxSteps - 1 && !hideIteration;
const hasFinish = !lockedEditor && currentStep == maxSteps - 1 && !hideIteration;
const hasFinish = !lockedEditor && currentStep == maxSteps - 1 && !hideIteration && !hideDone;
const hasHint = this.hasHint();
const tutorialCardContent = stepInfo.headerContentMd;
const showDialog = stepInfo.showDialog;
Expand Down

0 comments on commit 59a2b47

Please sign in to comment.